Commit ed625243 authored by attilak's avatar attilak

Merge branch 'PW-2212' into feature/generic-component

# Conflicts:
#	Block/Form/Cc.php
#	Gateway/Request/CcAuthorizationDataBuilder.php
#	Gateway/Request/CheckoutDataBuilder.php
#	Gateway/Request/RecurringDataBuilder.php
#	Gateway/Validator/CheckoutResponseValidator.php
#	Helper/PaymentMethods.php
#	Helper/Requests.php
#	Model/AdyenThreeDS2Process.php
#	Model/Ui/AdyenGenericConfigProvider.php
#	Observer/AdyenCcDataAssignObserver.php
#	Observer/AdyenHppDataAssignObserver.php
#	view/frontend/web/js/model/adyen-method-list.js
#	view/frontend/web/js/model/adyen-payment-service.js
#	view/frontend/web/js/view/payment/adyen-methods.js
#	view/frontend/web/js/view/payment/method-renderer/adyen-cc-method.js
#	view/frontend/web/js/view/payment/method-renderer/adyen-hpp-method.js
#	view/frontend/web/js/view/payment/method-renderer/adyen-oneclick-method.js
parents 7ee6f945 c6bdeeec
...@@ -67,22 +67,14 @@ class Cc extends \Magento\Payment\Block\Form\Cc ...@@ -67,22 +67,14 @@ class Cc extends \Magento\Payment\Block\Form\Cc
$this->checkoutSession = $checkoutSession; $this->checkoutSession = $checkoutSession;
} }
/** /**
* @return string * @return string
*/ * @throws \Adyen\AdyenException
public function getCheckoutCardComponentJs() */
{ public function getCheckoutOriginKeys()
return $this->adyenHelper->getCheckoutCardComponentJs($this->checkoutSession->getQuote()->getStore()->getId()); {
} return $this->adyenHelper->getOriginKeyForBaseUrl();
}
/**
* @return string
* @throws \Adyen\AdyenException
*/
public function getCheckoutOriginKeys()
{
return $this->adyenHelper->getOriginKeyForBaseUrl();
}
/** /**
* @return string * @return string
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2019 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
class CcAuthorizationDataBuilder implements BuilderInterface
{
/**
* @param array $buildSubject
* @return mixed
*/
public function build(array $buildSubject)
{
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$requestBody = [];
// If ccType is set use this. For bcmc you need bcmc otherwise it will fail
$requestBody['paymentMethod']['type'] = "scheme";
if ($cardNumber = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER)) {
$requestBody['paymentMethod']['encryptedCardNumber'] = $cardNumber;
}
if ($expiryMonth = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH)) {
$requestBody['paymentMethod']['encryptedExpiryMonth'] = $expiryMonth;
}
if ($expiryYear = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR)) {
$requestBody['paymentMethod']['encryptedExpiryYear'] = $expiryYear;
}
if ($holderName = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME)) {
$requestBody['paymentMethod']['holderName'] = $holderName;
}
if ($securityCode = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE)) {
$requestBody['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 installments is set and card type is credit card add it into the request
$numberOfInstallments = $payment->getAdditionalInformation(
AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS
) ?: 0;
$comboCardType = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::COMBO_CARD_TYPE) ?: 'credit';
if ($numberOfInstallments > 0) {
$requestBody['installments']['value'] = $numberOfInstallments;
}
// if card type is debit then change the issuer type and unset the installments field
if ($comboCardType == 'debit') {
if ($selectedDebitBrand = $this->getSelectedDebitBrand($payment->getAdditionalInformation('cc_type'))) {
$requestBody['additionalData']['overwriteBrand'] = true;
$requestBody['selectedBrand'] = $selectedDebitBrand;
$requestBody['paymentMethod']['type'] = $selectedDebitBrand;
}
unset($requestBody['installments']);
}
$request['body'] = $requestBody;
return $request;
}
/**
* @param string $brand
* @return string
*/
private function getSelectedDebitBrand($brand)
{
if ($brand == 'VI') {
return 'electron';
}
if ($brand == 'MC') {
return 'maestro';
}
return null;
}
}
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
namespace Adyen\Payment\Gateway\Request; namespace Adyen\Payment\Gateway\Request;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
use Magento\Payment\Gateway\Request\BuilderInterface; use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenHppDataAssignObserver; use Adyen\Payment\Observer\AdyenHppDataAssignObserver;
...@@ -82,14 +83,17 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -82,14 +83,17 @@ class CheckoutDataBuilder implements BuilderInterface
// do not send email // do not send email
$order->setCanSendNewEmailFlag(false); $order->setCanSendNewEmailFlag(false);
$requestBodyPaymentMethod['type'] = $payment->getAdditionalInformation( $componentStateData = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::STATE_DATA);
AdyenHppDataAssignObserver::BRAND_CODE $requestBody = array_merge($requestBody, $componentStateData);
);
// Additional data for payment methods with issuer list
if ($payment->getAdditionalInformation(AdyenHppDataAssignObserver::ISSUER_ID)) { if (empty($requestBody['paymentMethod']['type']) && !empty(
$requestBodyPaymentMethod['issuer'] = $payment->getAdditionalInformation( $payment->getAdditionalInformation(
AdyenHppDataAssignObserver::ISSUER_ID AdyenHppDataAssignObserver::BRAND_CODE
)
)) {
$requestBody['paymentMethod']['type'] = $payment->getAdditionalInformation(
AdyenHppDataAssignObserver::BRAND_CODE
); );
} }
...@@ -97,59 +101,24 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -97,59 +101,24 @@ class CheckoutDataBuilder implements BuilderInterface
\Magento\Framework\UrlInterface::URL_TYPE_LINK \Magento\Framework\UrlInterface::URL_TYPE_LINK
) . 'adyen/process/result'; ) . 'adyen/process/result';
// Additional data for ACH // TODO set order payment extra data -> mapping required
if ($payment->getAdditionalInformation("bankAccountNumber")) {
$requestBody['bankAccount']['bankAccountNumber'] = $payment->getAdditionalInformation("bankAccountNumber");
}
if ($payment->getAdditionalInformation("bankLocationId")) {
$requestBody['bankAccount']['bankLocationId'] = $payment->getAdditionalInformation("bankLocationId");
}
if ($payment->getAdditionalInformation("bankAccountOwnerName")) {
$requestBody['bankAccount']['ownerName'] = $payment->getAdditionalInformation("bankAccountOwnerName");
}
// Additional data for open invoice payment
if ($payment->getAdditionalInformation("gender")) { if ($payment->getAdditionalInformation("gender")) {
$order->setCustomerGender( $order->setCustomerGender(
$this->gender->getMagentoGenderFromAdyenGender( \Adyen\Payment\Model\Gender::getMagentoGenderFromAdyenGender(
$payment->getAdditionalInformation("gender") $payment->getAdditionalInformation("gender")
) )
); );
$requestBodyPaymentMethod['personalDetails']['gender'] = $payment->getAdditionalInformation("gender");
} }
if ($payment->getAdditionalInformation("dob")) { if ($payment->getAdditionalInformation("dob")) {
$order->setCustomerDob($payment->getAdditionalInformation("dob")); $order->setCustomerDob($payment->getAdditionalInformation("dob"));
$requestBodyPaymentMethod['personalDetails']['dateOfBirth'] = $this->adyenHelper->formatDate(
$payment->getAdditionalInformation("dob"),
'Y-m-d'
);
} }
if ($payment->getAdditionalInformation("telephone")) { if ($payment->getAdditionalInformation("telephone")) {
$order->getBillingAddress()->setTelephone($payment->getAdditionalInformation("telephone")); $order->getBillingAddress()->setTelephone($payment->getAdditionalInformation("telephone"));
$requestBodyPaymentMethod['personalDetails']['telephoneNumber'] = $payment->getAdditionalInformation(
"telephone"
);
}
if ($payment->getAdditionalInformation("ssn")) {
$requestBodyPaymentMethod['personalDetails']['socialSecurityNumber'] =
$payment->getAdditionalInformation("ssn");
}
// Additional data for sepa direct debit
if ($payment->getAdditionalInformation("ownerName")) {
$requestBodyPaymentMethod['sepa.ownerName'] = $payment->getAdditionalInformation("ownerName");
}
if ($payment->getAdditionalInformation("ibanNumber")) {
$requestBodyPaymentMethod['sepa.ibanNumber'] = $payment->getAdditionalInformation("ibanNumber");
} }
// TODO new function isOpenInvoiceLineItemNeeded
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod( if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE) $payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
) || $this->adyenHelper->isPaymentMethodAfterpayTouchMethod( ) || $this->adyenHelper->isPaymentMethodAfterpayTouchMethod(
...@@ -163,6 +132,7 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -163,6 +132,7 @@ class CheckoutDataBuilder implements BuilderInterface
} }
// Ratepay specific Fingerprint // Ratepay specific Fingerprint
// TODO check if this is still necessary or if there is a component that can handle this
if ($payment->getAdditionalInformation("df_value") && $this->adyenHelper->isPaymentMethodRatepayMethod( if ($payment->getAdditionalInformation("df_value") && $this->adyenHelper->isPaymentMethodRatepayMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE) $payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
)) { )) {
...@@ -183,16 +153,17 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -183,16 +153,17 @@ class CheckoutDataBuilder implements BuilderInterface
} }
if ($payment->getMethod() == \Adyen\Payment\Model\Ui\AdyenBoletoConfigProvider::CODE) { if ($payment->getMethod() == \Adyen\Payment\Model\Ui\AdyenBoletoConfigProvider::CODE) {
$boletoTypes = $this->adyenHelper->getAdyenBoletoConfigData('boletotypes'); // TODO check if this is coming from the component now
/*$boletoTypes = $this->adyenHelper->getAdyenBoletoConfigData('boletotypes');
$boletoTypes = explode(',', $boletoTypes); $boletoTypes = explode(',', $boletoTypes);
if (count($boletoTypes) == 1) { if (count($boletoTypes) == 1) {
$requestBody['selectedBrand'] = $boletoTypes[0]; $requestBody['selectedBrand'] = $boletoTypes[0];
$requestBodyPaymentMethod['type'] = $boletoTypes[0]; $requestBody['paymentMethod']['type'] = $boletoTypes[0];
} else { } else {
$requestBody['selectedBrand'] = $payment->getAdditionalInformation("boleto_type"); $requestBody['selectedBrand'] = $payment->getAdditionalInformation("boleto_type");
$requestBodyPaymentMethod['type'] = $payment->getAdditionalInformation("boleto_type"); $requestBody['paymentMethod']['type'] = $payment->getAdditionalInformation("boleto_type");
} }*/
$deliveryDays = (int)$this->adyenHelper->getAdyenBoletoConfigData("delivery_days", $storeId); $deliveryDays = (int)$this->adyenHelper->getAdyenBoletoConfigData("delivery_days", $storeId);
$deliveryDays = (!empty($deliveryDays)) ? $deliveryDays : 5; $deliveryDays = (!empty($deliveryDays)) ? $deliveryDays : 5;
...@@ -213,7 +184,23 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -213,7 +184,23 @@ class CheckoutDataBuilder implements BuilderInterface
$order->setCanSendNewEmailFlag(true); $order->setCanSendNewEmailFlag(true);
} }
$requestBody['paymentMethod'] = $requestBodyPaymentMethod; // if installments is set and card type is credit card add it into the request
$numberOfInstallments = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS) ?: 0;
$comboCardType = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::COMBO_CARD_TYPE) ?: 'credit';
if ($numberOfInstallments > 0) {
$requestBody['installments']['value'] = $numberOfInstallments;
}
// if card type is debit then change the issuer type and unset the installments field
if ($comboCardType == 'debit') {
if ($selectedDebitBrand = $this->getSelectedDebitBrand($payment->getAdditionalInformation('cc_type'))) {
$requestBody['additionalData']['overwriteBrand'] = true;
$requestBody['selectedBrand'] = $selectedDebitBrand;
$requestBody['paymentMethod']['type'] = $selectedDebitBrand;
}
unset($requestBody['installments']);
}
$request['body'] = $requestBody; $request['body'] = $requestBody;
return $request; return $request;
...@@ -312,4 +299,19 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -312,4 +299,19 @@ class CheckoutDataBuilder implements BuilderInterface
return $formFields; return $formFields;
} }
/**
* @param string $brand
* @return string
*/
private function getSelectedDebitBrand($brand)
{
if ($brand == 'VI') {
return 'electron';
}
if ($brand == 'MC') {
return 'maestro';
}
return null;
}
} }
...@@ -63,13 +63,7 @@ class RecurringDataBuilder implements BuilderInterface ...@@ -63,13 +63,7 @@ class RecurringDataBuilder implements BuilderInterface
$payment = $paymentDataObject->getPayment(); $payment = $paymentDataObject->getPayment();
$storeId = $payment->getOrder()->getStoreId(); $storeId = $payment->getOrder()->getStoreId();
$areaCode = $this->appState->getAreaCode(); $areaCode = $this->appState->getAreaCode();
$additionalInformation = $payment->getAdditionalInformation(); $request['body'] = $this->adyenRequestsHelper->buildRecurringData([], $areaCode, $storeId);
$request['body'] = $this->adyenRequestsHelper->buildRecurringData(
$areaCode,
$storeId,
$additionalInformation,
[]
);
return $request; return $request;
} }
} }
...@@ -69,21 +69,9 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -69,21 +69,9 @@ class CheckoutResponseValidator extends AbstractValidator
// validate result // validate result
if (!empty($response['resultCode'])) { if (!empty($response['resultCode'])) {
switch ($response['resultCode']) { switch ($response['resultCode']) {
case "IdentifyShopper":
$payment->setAdditionalInformation('threeDSType', $response['resultCode']);
$payment->setAdditionalInformation(
'threeDS2Token',
$response['authentication']['threeds2.fingerprintToken']
);
$payment->setAdditionalInformation('threeDS2PaymentData', $response['paymentData']);
break;
case "ChallengeShopper": case "ChallengeShopper":
$payment->setAdditionalInformation('threeDSType', $response['resultCode']); case "IdentifyShopper":
$payment->setAdditionalInformation( $payment->setAdditionalInformation('action', $response['action']);
'threeDS2Token',
$response['authentication']['threeds2.challengeToken']
);
$payment->setAdditionalInformation('threeDS2PaymentData', $response['paymentData']);
break; break;
case "Authorised": case "Authorised":
case "Received": case "Received":
......
...@@ -39,11 +39,6 @@ class InstallmentValidator extends AbstractValidator ...@@ -39,11 +39,6 @@ class InstallmentValidator extends AbstractValidator
*/ */
private $adyenHelper; private $adyenHelper;
/**
* @var \Magento\Framework\Serialize\SerializerInterface
*/
private $serializer;
/** /**
* @var \Magento\Quote\Model\QuoteRepository * @var \Magento\Quote\Model\QuoteRepository
*/ */
...@@ -55,19 +50,16 @@ class InstallmentValidator extends AbstractValidator ...@@ -55,19 +50,16 @@ class InstallmentValidator extends AbstractValidator
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory * @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger * @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Adyen\Payment\Helper\Data $adyenHelper * @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Serialize\SerializerInterface $serializer
* @param \Magento\Quote\Model\QuoteRepository $quoteRepository * @param \Magento\Quote\Model\QuoteRepository $quoteRepository
*/ */
public function __construct( public function __construct(
\Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory, \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger, \Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Adyen\Payment\Helper\Data $adyenHelper, \Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Serialize\SerializerInterface $serializer,
\Magento\Quote\Model\QuoteRepository $quoteRepository \Magento\Quote\Model\QuoteRepository $quoteRepository
) { ) {
$this->adyenLogger = $adyenLogger; $this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper; $this->adyenHelper = $adyenHelper;
$this->serializer = $serializer;
$this->quoteRepository = $quoteRepository; $this->quoteRepository = $quoteRepository;
parent::__construct($resultFactory); parent::__construct($resultFactory);
} }
...@@ -87,27 +79,14 @@ class InstallmentValidator extends AbstractValidator ...@@ -87,27 +79,14 @@ class InstallmentValidator extends AbstractValidator
$installmentsEnabled = $this->adyenHelper->getAdyenCcConfigData('enable_installments'); $installmentsEnabled = $this->adyenHelper->getAdyenCcConfigData('enable_installments');
if ($quote && $installmentsEnabled) { if ($quote && $installmentsEnabled) {
$grandTotal = $quote->getGrandTotal(); $grandTotal = $quote->getGrandTotal();
$installmentsAvailable = $this->adyenHelper->getAdyenCcConfigData('installments'); $installments = $this->adyenHelper->getAdyenCcConfigData('installments');
$installmentSelected = $payment->getAdditionalInformation('number_of_installments'); $installmentSelected = $payment->getAdditionalInformation('number_of_installments');
$ccType = $payment->getAdditionalInformation('cc_type'); $ccType = $payment->getAdditionalInformation('cc_type');
if ($installmentsAvailable) {
$installments = $this->serializer->unserialize($installmentsAvailable);
}
if ($installmentSelected && $installmentsAvailable) { if ($installmentSelected && $installmentsAvailable) {
$isValid = false; $isValid = false;
$fails[] = __('Installments not valid.'); $fails[] = __('Installments not valid.');
if ($installments) { if ($installments) {
foreach ($installments as $ccTypeInstallment => $installment) { //TODO how implement custom validation of generated installments code against selected value?
if ($ccTypeInstallment == $ccType) {
foreach ($installment as $amount => $installmentsData) {
if ($installmentSelected == $installmentsData) {
if ($grandTotal >= $amount) {
$isValid = true;
}
}
}
}
}
} }
} }
} }
......
...@@ -34,8 +34,6 @@ class Data extends AbstractHelper ...@@ -34,8 +34,6 @@ class Data extends AbstractHelper
const MODULE_NAME = 'adyen-magento2'; const MODULE_NAME = 'adyen-magento2';
const TEST = 'test'; const TEST = 'test';
const LIVE = 'live'; const LIVE = 'live';
const CHECKOUT_COMPONENT_JS_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/3.2.0/adyen.js';
const CHECKOUT_COMPONENT_JS_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.2.0/adyen.js';
/** /**
* @var \Magento\Framework\Encryption\EncryptorInterface * @var \Magento\Framework\Encryption\EncryptorInterface
...@@ -1626,19 +1624,6 @@ class Data extends AbstractHelper ...@@ -1626,19 +1624,6 @@ class Data extends AbstractHelper
return new \Adyen\Service\CheckoutUtility($client); return new \Adyen\Service\CheckoutUtility($client);
} }
/**
* @param int|null $storeId
* @return string
*/
public function getCheckoutCardComponentJs($storeId = null)
{
if ($this->isDemoMode($storeId)) {
return self::CHECKOUT_COMPONENT_JS_TEST;
}
return self::CHECKOUT_COMPONENT_JS_LIVE;
}
/** /**
* @param $order * @param $order
* @param $additionalData * @param $additionalData
...@@ -1827,27 +1812,6 @@ class Data extends AbstractHelper ...@@ -1827,27 +1812,6 @@ class Data extends AbstractHelper
return $timeStamp->format($format); return $timeStamp->format($format);
} }
/**
* @param string|null $type
* @param string|null $token
* @return string
*/
public function buildThreeDS2ProcessResponseJson($type = null, $token = null)
{
$response = ['threeDS2' => false];
if (!empty($type)) {
$response['type'] = $type;
}
if ($type && $token) {
$response['threeDS2'] = true;
$response['token'] = $token;
}
return json_encode($response);
}
/** /**
* @param int $storeId * @param int $storeId
* @return mixed|string * @return mixed|string
......
...@@ -90,6 +90,11 @@ class PaymentMethods extends AbstractHelper ...@@ -90,6 +90,11 @@ class PaymentMethods extends AbstractHelper
*/ */
protected $quote; protected $quote;
/**
* @var \Magento\Checkout\Model\PaymentDetailsFactory
*/
protected $paymentDetailsFactory;
/** /**
* PaymentMethods constructor. * PaymentMethods constructor.
* *
...@@ -104,6 +109,7 @@ class PaymentMethods extends AbstractHelper ...@@ -104,6 +109,7 @@ class PaymentMethods extends AbstractHelper
* @param \Magento\Framework\View\Asset\Source $assetSource * @param \Magento\Framework\View\Asset\Source $assetSource
* @param \Magento\Framework\View\DesignInterface $design * @param \Magento\Framework\View\DesignInterface $design
* @param \Magento\Framework\View\Design\Theme\ThemeProviderInterface $themeProvider * @param \Magento\Framework\View\Design\Theme\ThemeProviderInterface $themeProvider
* @param \Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory
*/ */
public function __construct( public function __construct(
\Magento\Quote\Api\CartRepositoryInterface $quoteRepository, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
...@@ -116,7 +122,8 @@ class PaymentMethods extends AbstractHelper ...@@ -116,7 +122,8 @@ class PaymentMethods extends AbstractHelper
\Magento\Framework\App\RequestInterface $request, \Magento\Framework\App\RequestInterface $request,
\Magento\Framework\View\Asset\Source $assetSource, \Magento\Framework\View\Asset\Source $assetSource,
\Magento\Framework\View\DesignInterface $design, \Magento\Framework\View\DesignInterface $design,
\Magento\Framework\View\Design\Theme\ThemeProviderInterface $themeProvider \Magento\Framework\View\Design\Theme\ThemeProviderInterface $themeProvider,
\Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory
) { ) {
$this->quoteRepository = $quoteRepository; $this->quoteRepository = $quoteRepository;
$this->config = $config; $this->config = $config;
...@@ -129,6 +136,7 @@ class PaymentMethods extends AbstractHelper ...@@ -129,6 +136,7 @@ class PaymentMethods extends AbstractHelper
$this->assetSource = $assetSource; $this->assetSource = $assetSource;
$this->design = $design; $this->design = $design;
$this->themeProvider = $themeProvider; $this->themeProvider = $themeProvider;
$this->paymentDetailsFactory = $paymentDetailsFactory;
} }
/** /**
...@@ -146,7 +154,7 @@ class PaymentMethods extends AbstractHelper ...@@ -146,7 +154,7 @@ class PaymentMethods extends AbstractHelper
$this->setQuote($quote); $this->setQuote($quote);
$paymentMethods = $this->fetchAlternativeMethods($country); $paymentMethods = $this->fetchPaymentMethods($country);
return $paymentMethods; return $paymentMethods;
} }
...@@ -154,7 +162,7 @@ class PaymentMethods extends AbstractHelper ...@@ -154,7 +162,7 @@ class PaymentMethods extends AbstractHelper
* @param $country * @param $country
* @return array * @return array
*/ */
protected function fetchAlternativeMethods($country) protected function fetchPaymentMethods($country)
{ {
$quote = $this->getQuote(); $quote = $this->getQuote();
$store = $quote->getStore(); $store = $quote->getStore();
...@@ -192,64 +200,78 @@ class PaymentMethods extends AbstractHelper ...@@ -192,64 +200,78 @@ class PaymentMethods extends AbstractHelper
$responseData = $this->getPaymentMethodsResponse($adyFields, $store); $responseData = $this->getPaymentMethodsResponse($adyFields, $store);
$paymentMethods = []; if (empty($responseData['paymentMethods'])) {
if (isset($responseData['paymentMethods'])) { return [];
foreach ($responseData['paymentMethods'] as $paymentMethod) { }
$paymentMethods = $responseData['paymentMethods'];
$response['paymentMethodsResponse'] = $responseData;
// Add extra details per payment mmethod
$paymentMethodsExtraDetails = [];
if ($this->adyenHelper->showLogos()) {
// Explicitly setting theme
$themeCode = "Magento/blank";
$themeId = $this->design->getConfigurationDesignTheme(\Magento\Framework\App\Area::AREA_FRONTEND);
if (!empty($themeId)) {
$theme = $this->themeProvider->getThemeById($themeId);
if ($theme && !empty($theme->getCode())) {
$themeCode = $theme->getCode();
}
}
$params = [];
$params = array_merge(
[
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
'_secure' => $this->request->isSecure(),
'theme' => $themeCode
],
$params
);
foreach ($paymentMethods as $paymentMethod) {
$paymentMethodCode = $paymentMethod['type']; $paymentMethodCode = $paymentMethod['type'];
$paymentMethod = $this->fieldMapPaymentMethod($paymentMethod);
$asset = $this->assetRepo->createAsset(
'Adyen_Payment::images/logos/' .
$paymentMethodCode . '.png',
$params
);
$placeholder = $this->assetSource->findSource($asset);
$icon = [];
if ($placeholder) {
list($width, $height) = getimagesize($asset->getSourceFile());
$icon = [
'url' => $asset->getUrl(),
'width' => $width,
'height' => $height
];
} else {
$icon = [
'url' => 'https://checkoutshopper-live.adyen.com/checkoutshopper/images/logos/medium/' .$paymentMethodCode . '.png',
'width' => 77,
'height' => 50
];
}
$paymentMethodsExtraDetails[$paymentMethodCode]['icon'] = $icon;
// check if payment method is an openinvoice method // check if payment method is an openinvoice method
$paymentMethod['isPaymentMethodOpenInvoiceMethod'] = $paymentMethodsExtraDetails[$paymentMethodCode]['isOpenInvoice'] =
$this->adyenHelper->isPaymentMethodOpenInvoiceMethod($paymentMethodCode); $this->adyenHelper->isPaymentMethodOpenInvoiceMethod($paymentMethodCode);
// add icon location in result
if ($this->adyenHelper->showLogos()) {
// Fix for MAGETWO-70402 https://github.com/magento/magento2/pull/7686
// Explicitly setting theme
$themeCode = "Magento/blank";
$themeId = $this->design->getConfigurationDesignTheme(\Magento\Framework\App\Area::AREA_FRONTEND);
if (!empty($themeId)) {
$theme = $this->themeProvider->getThemeById($themeId);
if ($theme && !empty($theme->getCode())) {
$themeCode = $theme->getCode();
}
}
$params = [];
$params = array_merge(
[
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
'_secure' => $this->request->isSecure(),
'theme' => $themeCode
],
$params
);
$asset = $this->assetRepo->createAsset(
'Adyen_Payment::images/logos/' .
$paymentMethodCode . '.png',
$params
);
$placeholder = $this->assetSource->findSource($asset);
$icon = null;
if ($placeholder) {
list($width, $height) = getimagesize($asset->getSourceFile());
$icon = [
'url' => $asset->getUrl(),
'width' => $width,
'height' => $height
];
}
$paymentMethod['icon'] = $icon;
}
$paymentMethods[$paymentMethodCode] = $paymentMethod;
} }
} }
return $paymentMethods; $response['paymentMethodsExtraDetails'] = $paymentMethodsExtraDetails;
//TODO this should be the implemented with an interface
return json_encode($response);
} }
/** /**
...@@ -306,28 +328,6 @@ class PaymentMethods extends AbstractHelper ...@@ -306,28 +328,6 @@ class PaymentMethods extends AbstractHelper
return ""; return "";
} }
/**
* @var array
*/
protected $fieldMapPaymentMethod = [
'name' => 'title'
];
/**
* @param $paymentMethod
* @return mixed
*/
protected function fieldMapPaymentMethod($paymentMethod)
{
foreach ($this->fieldMapPaymentMethod as $field => $newField) {
if (isset($paymentMethod[$field])) {
$paymentMethod[$newField] = $paymentMethod[$field];
unset($paymentMethod[$field]);
}
}
return $paymentMethod;
}
/** /**
* @param $requestParams * @param $requestParams
* @param $store * @param $store
......
...@@ -315,17 +315,6 @@ class Requests extends AbstractHelper ...@@ -315,17 +315,6 @@ class Requests extends AbstractHelper
$request['additionalData']['allow3DS2'] = true; $request['additionalData']['allow3DS2'] = true;
$request['origin'] = $this->adyenHelper->getOrigin(); $request['origin'] = $this->adyenHelper->getOrigin();
$request['channel'] = 'web'; $request['channel'] = 'web';
$request['browserInfo']['screenWidth'] = $additionalData[AdyenCcDataAssignObserver::SCREEN_WIDTH];
$request['browserInfo']['screenHeight'] = $additionalData[AdyenCcDataAssignObserver::SCREEN_HEIGHT];
$request['browserInfo']['colorDepth'] = $additionalData[AdyenCcDataAssignObserver::SCREEN_COLOR_DEPTH];
$request['browserInfo']['timeZoneOffset'] = $additionalData[AdyenCcDataAssignObserver::TIMEZONE_OFFSET];
$request['browserInfo']['language'] = $additionalData[AdyenCcDataAssignObserver::LANGUAGE];
if ($javaEnabled = $additionalData[AdyenCcDataAssignObserver::JAVA_ENABLED]) {
$request['browserInfo']['javaEnabled'] = $javaEnabled;
} else {
$request['browserInfo']['javaEnabled'] = false;
}
} else { } else {
$request['additionalData']['allow3DS2'] = false; $request['additionalData']['allow3DS2'] = false;
$request['origin'] = $this->adyenHelper->getOrigin(); $request['origin'] = $this->adyenHelper->getOrigin();
...@@ -341,7 +330,7 @@ class Requests extends AbstractHelper ...@@ -341,7 +330,7 @@ class Requests extends AbstractHelper
* @param $storeId * @param $storeId
* @param $payment * @param $payment
*/ */
public function buildRecurringData($areaCode, int $storeId, $additionalData, $request = []) public function buildRecurringData($areaCode, int $storeId, $request = [])
{ {
// If the vault feature is on this logic is handled in the VaultDataBuilder // If the vault feature is on this logic is handled in the VaultDataBuilder
if (!$this->adyenHelper->isCreditCardVaultEnabled()) { if (!$this->adyenHelper->isCreditCardVaultEnabled()) {
...@@ -363,11 +352,6 @@ class Requests extends AbstractHelper ...@@ -363,11 +352,6 @@ class Requests extends AbstractHelper
} else { } else {
$request['enableRecurring'] = false; $request['enableRecurring'] = false;
} }
// value can be 0,1 or true
if (!empty($additionalData[AdyenCcDataAssignObserver::STORE_CC])) {
$request['paymentMethod']['storeDetails'] = true;
}
} }
return $request; return $request;
......
...@@ -75,18 +75,11 @@ class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentSta ...@@ -75,18 +75,11 @@ class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentSta
) { ) {
$additionalInformation = $payment->getAdditionalInformation(); $additionalInformation = $payment->getAdditionalInformation();
$type = null; if (!empty($additionalInformation['action'])) {
if (!empty($additionalInformation['threeDSType'])) { return json_encode($additionalInformation['action']);
$type = $additionalInformation['threeDSType'];
} }
$token = null;
if (!empty($additionalInformation['threeDS2Token'])) {
$token = $additionalInformation['threeDS2Token'];
}
return $this->adyenHelper->buildThreeDS2ProcessResponseJson($type, $token);
} }
return true; return true;
} }
} }
...@@ -75,6 +75,7 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface ...@@ -75,6 +75,7 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
public function initiate($payload) public function initiate($payload)
{ {
// Decode payload from frontend // Decode payload from frontend
// TODO implement interface to handle the request the correct way
$payload = json_decode($payload, true); $payload = json_decode($payload, true);
// Validate JSON that has just been parsed if it was in a valid format // Validate JSON that has just been parsed if it was in a valid format
...@@ -84,6 +85,7 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface ...@@ -84,6 +85,7 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
); );
} }
// Validate if order id is present
if (empty($payload['orderId'])) { if (empty($payload['orderId'])) {
$order = $this->getOrder(); $order = $this->getOrder();
// In the next major release remove support for retrieving order from session and throw exception instead // In the next major release remove support for retrieving order from session and throw exception instead
...@@ -96,30 +98,16 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface ...@@ -96,30 +98,16 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
$payment = $order->getPayment(); $payment = $order->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 // Unset action from additional info since it is not needed anymore
$payment->unsAdditionalInformation("threeDS2PaymentData"); $payment->unsAdditionalInformation("action");
} else {
$this->adyenLogger->error("3D secure 2.0 failed, payment data not found");
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 // TODO validate and format the request root level keys
if (!empty($payload['details']['threeds2.fingerprint'])) { $request = $payload;
$request['details']['threeds2.fingerprint'] = $payload['details']['threeds2.fingerprint'];
} elseif (!empty($payload['details']['threeds2.challengeResult'])) { // Init payments/details request
$request['details']['threeds2.challengeResult'] = $payload['details']['threeds2.challengeResult']; $result = [];
}
// Send the request // Send the request
try { try {
...@@ -135,12 +123,9 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface ...@@ -135,12 +123,9 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
// Check if result is challenge shopper, if yes return the token // Check if result is challenge shopper, if yes return the token
if (!empty($result['resultCode']) && if (!empty($result['resultCode']) &&
$result['resultCode'] === 'ChallengeShopper' && $result['resultCode'] === 'ChallengeShopper' &&
!empty($result['authentication']['threeds2.challengeToken']) !empty($result['action'])
) { ) {
return $this->adyenHelper->buildThreeDS2ProcessResponseJson( return json_encode($result['action']);
$result['resultCode'],
$result['authentication']['threeds2.challengeToken']
);
} }
// Save the payments response because we are going to need it during the place order flow // Save the payments response because we are going to need it during the place order flow
......
...@@ -59,6 +59,8 @@ class GuestAdyenPaymentMethodManagement implements \Adyen\Payment\Api\GuestAdyen ...@@ -59,6 +59,8 @@ class GuestAdyenPaymentMethodManagement implements \Adyen\Payment\Api\GuestAdyen
// if shippingAddress is provided use this country // if shippingAddress is provided use this country
$country = null; $country = null;
// TODO check why the frontend doesn't have the shipping address
// or get it from the cart
if ($shippingAddress) { if ($shippingAddress) {
$country = $shippingAddress->getCountryId(); $country = $shippingAddress->getCountryId();
} }
......
...@@ -67,11 +67,6 @@ class AdyenCcConfigProvider implements ConfigProviderInterface ...@@ -67,11 +67,6 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
*/ */
private $storeManager; private $storeManager;
/**
* @var \Magento\Framework\Serialize\SerializerInterface
*/
private $serializer;
/** /**
* AdyenCcConfigProvider constructor. * AdyenCcConfigProvider constructor.
* *
...@@ -82,7 +77,6 @@ class AdyenCcConfigProvider implements ConfigProviderInterface ...@@ -82,7 +77,6 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
* @param \Magento\Framework\View\Asset\Source $assetSource * @param \Magento\Framework\View\Asset\Source $assetSource
* @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Payment\Model\CcConfig $ccConfig * @param \Magento\Payment\Model\CcConfig $ccConfig
* @param \Magento\Framework\Serialize\SerializerInterface $serializer
*/ */
public function __construct( public function __construct(
\Magento\Payment\Helper\Data $paymentHelper, \Magento\Payment\Helper\Data $paymentHelper,
...@@ -91,8 +85,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface ...@@ -91,8 +85,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
\Magento\Framework\UrlInterface $urlBuilder, \Magento\Framework\UrlInterface $urlBuilder,
\Magento\Framework\View\Asset\Source $assetSource, \Magento\Framework\View\Asset\Source $assetSource,
\Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Payment\Model\CcConfig $ccConfig, \Magento\Payment\Model\CcConfig $ccConfig
\Magento\Framework\Serialize\SerializerInterface $serializer
) { ) {
$this->_paymentHelper = $paymentHelper; $this->_paymentHelper = $paymentHelper;
$this->_adyenHelper = $adyenHelper; $this->_adyenHelper = $adyenHelper;
...@@ -101,7 +94,6 @@ class AdyenCcConfigProvider implements ConfigProviderInterface ...@@ -101,7 +94,6 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
$this->_assetSource = $assetSource; $this->_assetSource = $assetSource;
$this->ccConfig = $ccConfig; $this->ccConfig = $ccConfig;
$this->storeManager = $storeManager; $this->storeManager = $storeManager;
$this->serializer = $serializer;
} }
/** /**
...@@ -170,7 +162,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface ...@@ -170,7 +162,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
$installments = $this->_adyenHelper->getAdyenCcConfigData('installments'); $installments = $this->_adyenHelper->getAdyenCcConfigData('installments');
if ($installmentsEnabled && $installments) { if ($installmentsEnabled && $installments) {
$config['payment']['adyenCc']['installments'] = $this->serializer->unserialize($installments); $config['payment']['adyenCc']['installments'] = $installments;
$config['payment']['adyenCc']['hasInstallments'] = true; $config['payment']['adyenCc']['hasInstallments'] = true;
} else { } else {
$config['payment']['adyenCc']['installments'] = []; $config['payment']['adyenCc']['installments'] = [];
......
...@@ -69,10 +69,6 @@ class AdyenGenericConfigProvider implements ConfigProviderInterface ...@@ -69,10 +69,6 @@ class AdyenGenericConfigProvider implements ConfigProviderInterface
$config['payment']['adyen']['showLogo'] = false; $config['payment']['adyen']['showLogo'] = false;
} }
$config['payment']['checkoutCardComponentSource'] = $this->_adyenHelper->getCheckoutCardComponentJs(
$this->storeManager->getStore()->getId()
);
return $config; return $config;
} }
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Observer;
use Magento\Framework\DataObject;
use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface;
abstract class AdyenAbstractDataAssignObserver extends AbstractDataAssignObserver
{
const BRAND_CODE = 'brand_code';
const STATE_DATA = 'state_data';
const BROWSER_INFO = 'browserInfo';
const PAYMENT_METHOD = 'paymentMethod';
const RISK_DATA = 'riskData';
const STORE_PAYMENT_METHOD = 'storePaymentMethod';
const CC_TYPE = 'cc_type';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const COMBO_CARD_TYPE = 'combo_card_type';
/**
* @param DataObject $data
* @return array
*/
protected function getValidatedAdditionalData(DataObject $data)
{
// Get additional data array
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
if (!is_array($additionalData)) {
return [];
}
// Get a validated additional data array
$additionalData = $this->getArrayOnlyWithApprovedKeys($additionalData, $this->approvedAdditionalDataKeys);
// json decode state data
$stateData = [];
if (!empty($additionalData[self::STATE_DATA])) {
$stateData = json_decode($additionalData[self::STATE_DATA], true);
}
// Get validated state data array
if (!empty($stateData)) {
$stateData = $this->getArrayOnlyWithApprovedKeys($stateData, $this->approvedStateDataKeys);
}
// Replace state data with the decoded and validated state data
$additionalData[self::STATE_DATA] = $stateData;
return $additionalData;
}
/**
* Returns an array with only the approved keys
*
* @param array $array
* @param array $approvedKeys
* @return array
*/
private function getArrayOnlyWithApprovedKeys($array, $approvedKeys)
{
$result = [];
foreach ($approvedKeys as $approvedKey) {
if (isset($array[$approvedKey])) {
$result[$approvedKey] = $array[$approvedKey];
}
}
return $result;
}
}
...@@ -24,50 +24,31 @@ ...@@ -24,50 +24,31 @@
namespace Adyen\Payment\Observer; namespace Adyen\Payment\Observer;
use Magento\Framework\Event\Observer; use Magento\Framework\Event\Observer;
use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Api\Data\PaymentInterface;
class AdyenCcDataAssignObserver extends AbstractDataAssignObserver class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
{ {
const CC_TYPE = 'cc_type'; /**
const NUMBER_OF_INSTALLMENTS = 'number_of_installments'; * Approved root level keys from additional data array
const STORE_CC = 'store_cc'; *
const ENCRYPTED_CREDIT_CARD_NUMBER = 'number'; * @var array
const ENCRYPTED_SECURITY_CODE = 'cvc'; */
const ENCRYPTED_EXPIRY_MONTH = 'expiryMonth'; protected $approvedAdditionalDataKeys = [
const ENCRYPTED_EXPIRY_YEAR = 'expiryYear'; self::STATE_DATA,
const HOLDER_NAME = 'holderName'; self::COMBO_CARD_TYPE,
const VARIANT = 'variant'; self::NUMBER_OF_INSTALLMENTS
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';
const GUEST_EMAIL = 'guestEmail';
const COMBO_CARD_TYPE = 'combo_card_type';
/** /**
* Approved root level keys from the checkout component's state data object
*
* @var array * @var array
*/ */
protected $additionalInformationList = [ protected $approvedStateDataKeys = [
self::CC_TYPE, self::BROWSER_INFO,
self::NUMBER_OF_INSTALLMENTS, self::PAYMENT_METHOD,
self::STORE_CC, self::RISK_DATA,
self::ENCRYPTED_CREDIT_CARD_NUMBER, self::STORE_PAYMENT_METHOD
self::ENCRYPTED_SECURITY_CODE,
self::ENCRYPTED_EXPIRY_MONTH,
self::ENCRYPTED_EXPIRY_YEAR,
self::HOLDER_NAME,
self::VARIANT,
self::JAVA_ENABLED,
self::SCREEN_COLOR_DEPTH,
self::SCREEN_WIDTH,
self::SCREEN_HEIGHT,
self::TIMEZONE_OFFSET,
self::LANGUAGE,
self::GUEST_EMAIL,
self::COMBO_CARD_TYPE
]; ];
/** /**
...@@ -76,27 +57,20 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver ...@@ -76,27 +57,20 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
*/ */
public function execute(Observer $observer) public function execute(Observer $observer)
{ {
// Get request fields
$data = $this->readDataArgument($observer); $data = $this->readDataArgument($observer);
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA); $additionalData = $this->getValidatedAdditionalData($data);
if (!is_array($additionalData)) {
return;
}
// Set additional data in the payment
$paymentInfo = $this->readPaymentModelArgument($observer); $paymentInfo = $this->readPaymentModelArgument($observer);
foreach ($additionalData as $key => $data) {
// set ccType $paymentInfo->setAdditionalInformation($key, $data);
if (!empty($additionalData['cc_type'])) {
$paymentInfo->setCcType($additionalData['cc_type']);
} }
foreach ($this->additionalInformationList as $additionalInformationKey) { // set ccType
if (isset($additionalData[$additionalInformationKey])) { if (!empty($additionalData[self::CC_TYPE])) {
$paymentInfo->setAdditionalInformation( $paymentInfo->setCcType($additionalData[self::CC_TYPE]);
$additionalInformationKey,
$additionalData[$additionalInformationKey]
);
}
} }
} }
} }
...@@ -24,40 +24,29 @@ ...@@ -24,40 +24,29 @@
namespace Adyen\Payment\Observer; namespace Adyen\Payment\Observer;
use Magento\Framework\Event\Observer; use Magento\Framework\Event\Observer;
use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Api\Data\PaymentInterface;
class AdyenHppDataAssignObserver extends AbstractDataAssignObserver class AdyenHppDataAssignObserver extends AbstractDataAssignObserver
{ {
const BRAND_CODE = 'brand_code'; /**
const ISSUER_ID = 'issuer_id'; * Approved root level keys from additional data array
const GENDER = 'gender'; *
const DOB = 'dob'; * @var array
const TELEPHONE = 'telephone'; */
const DF_VALUE = 'df_value'; protected $approvedAdditionalDataKeys = [
const SSN = 'ssn'; self::STATE_DATA,
const OWNER_NAME = 'ownerName'; self::BRAND_CODE
const BANK_ACCOUNT_OWNER_NAME = 'bankAccountOwnerName'; ];
const IBAN_NUMBER = 'ibanNumber';
const BANK_ACCOUNT_NUMBER = 'bankAccountNumber';
const BANK_LOCATIONID = 'bankLocationId';
/** /**
* Approved root level keys from the checkout component's state data object
*
* @var array * @var array
*/ */
protected $additionalInformationList = [ protected $approvedStateDataKeys = [
self::BRAND_CODE, self::BROWSER_INFO,
self::ISSUER_ID, self::PAYMENT_METHOD,
self::GENDER, self::RISK_DATA
self::DOB,
self::TELEPHONE,
self::DF_VALUE,
self::SSN,
self::OWNER_NAME,
self::BANK_ACCOUNT_OWNER_NAME,
self::IBAN_NUMBER,
self::BANK_ACCOUNT_NUMBER,
self::BANK_LOCATIONID
]; ];
/** /**
...@@ -66,26 +55,20 @@ class AdyenHppDataAssignObserver extends AbstractDataAssignObserver ...@@ -66,26 +55,20 @@ class AdyenHppDataAssignObserver extends AbstractDataAssignObserver
*/ */
public function execute(Observer $observer) public function execute(Observer $observer)
{ {
// Get request fields
$data = $this->readDataArgument($observer); $data = $this->readDataArgument($observer);
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA); $additionalData = $this->getValidatedAdditionalData($data);
if (!is_array($additionalData)) {
return;
}
// Set additional data in the payment
$paymentInfo = $this->readPaymentModelArgument($observer); $paymentInfo = $this->readPaymentModelArgument($observer);
foreach ($additionalData as $key => $data) {
$paymentInfo->setAdditionalInformation($key, $data);
}
// Set BrandCode into CCType
if (isset($additionalData[self::BRAND_CODE])) { if (isset($additionalData[self::BRAND_CODE])) {
$paymentInfo->setCcType($additionalData[self::BRAND_CODE]); $paymentInfo->setCcType($additionalData[self::BRAND_CODE]);
} }
foreach ($this->additionalInformationList as $additionalInformationKey) {
if (isset($additionalData[$additionalInformationKey])) {
$paymentInfo->setAdditionalInformation(
$additionalInformationKey,
$additionalData[$additionalInformationKey]
);
}
}
} }
} }
...@@ -77,20 +77,17 @@ ...@@ -77,20 +77,17 @@
<tooltip>Enable installments for each credit card type.</tooltip> <tooltip>Enable installments for each credit card type.</tooltip>
<config_path>payment/adyen_cc/enable_installments</config_path> <config_path>payment/adyen_cc/enable_installments</config_path>
</field> </field>
<field id="installments" translate="label" sortOrder="220" showInDefault="1" showInWebsite="1" <field id="installments" type="textarea" translate="label" sortOrder="220" showInDefault="1"
showInStore="1"> showInWebsite="1" showInStore="1">
<label>Installments</label> <label>Installments</label>
<depends> <depends>
<field id="enable_installments">1</field> <field id="enable_installments">1</field>
</depends> </depends>
<tooltip>Configure your installment for each credit card type: Insert the minimum amount required to <validate>required-entry</validate>
make the configured installment available in the amount range column. <comment><![CDATA[
Example: if the amount range is configured to 100 and the number of installments to 4x, the shopper Generate the desired installments configuration <a href="">here</a> and paste it on this field.
will see the 4x option only if the payment total is higher or equal than 100. ]]></comment>
</tooltip> <config_path>payment/adyen_cc/installments_code</config_path>
<frontend_model>Adyen\Payment\Block\Adminhtml\System\Config\Field\Installments</frontend_model>
<backend_model>Adyen\Payment\Model\Config\Backend\Installments</backend_model>
<config_path>payment/adyen_cc/installments</config_path>
</field> </field>
</group> </group>
......
...@@ -557,7 +557,7 @@ ...@@ -557,7 +557,7 @@
<item name="payment" xsi:type="string">Adyen\Payment\Gateway\Request\PaymentDataBuilder</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="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item> <item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder</item> <item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CheckoutDataBuilder</item>
<item name="vault" xsi:type="string">Adyen\Payment\Gateway\Request\VaultDataBuilder</item> <item name="vault" xsi:type="string">Adyen\Payment\Gateway\Request\VaultDataBuilder</item>
<item name="threeds2" xsi:type="string">Adyen\Payment\Gateway\Request\ThreeDS2DataBuilder</item> <item name="threeds2" xsi:type="string">Adyen\Payment\Gateway\Request\ThreeDS2DataBuilder</item>
</argument> </argument>
...@@ -990,11 +990,6 @@ ...@@ -990,11 +990,6 @@
<argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Serialize</argument> <argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Serialize</argument>
</arguments> </arguments>
</type> </type>
<type name="Adyen\Payment\Gateway\Validator\InstallmentValidator">
<arguments>
<argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Serialize</argument>
</arguments>
</type>
<type name="Adyen\Payment\Model\Ui\AdyenPosCloudConfigProvider"> <type name="Adyen\Payment\Model\Ui\AdyenPosCloudConfigProvider">
<arguments> <arguments>
<argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Serialize</argument> <argument name="serializer" xsi:type="object">Magento\Framework\Serialize\Serializer\Serialize</argument>
......
...@@ -229,1394 +229,48 @@ ...@@ -229,1394 +229,48 @@
display: none; display: none;
} }
/* Checkout component Adyen v3.2.0 styling start */ /* Checkout component Adyen v3.7.0 styling start */
.adyen-checkout__field{ .adyen-checkout__fieldset{display:block;padding-bottom:8px;width:100%}.adyen-checkout__fieldset:last-of-type{padding-bottom:0}.adyen-checkout__fieldset+.adyen-checkout__fieldset{margin-top:16px}.adyen-checkout__fieldset__title{color:#687282;display:block;font-size:.68em;font-weight:700;letter-spacing:1px;margin:0;padding:0 0 12px;text-transform:uppercase}.adyen-checkout__field-group,.adyen-checkout__fieldset__fields{display:-webkit-box;display:flex;flex-wrap:wrap;-webkit-box-pack:justify;justify-content:space-between;width:100%}.adyen-checkout__field-group:last-of-type .adyen-checkout__field{margin-bottom:0}.adyen-checkout__fieldset--readonly .adyen-checkout__fieldset__fields{color:#00112c;font-size:.81em;line-height:19px;margin:0}
display:block; .adyen-checkout__field{display:block;margin-bottom:16px;width:100%}.adyen-checkout__field:last-of-type{margin-bottom:0}.adyen-checkout__label{display:block}.adyen-checkout__helper-text,.adyen-checkout__label__text{color:#00112c;display:block;font-size:.81em;font-weight:400;line-height:13px;padding-bottom:5px}.adyen-checkout__helper-text{color:#687282}.adyen-checkout__label__text{-webkit-transition:color .1s ease-out;transition:color .1s ease-out;display:block;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.adyen-checkout__label__text--error{color:#d10244}.adyen-checkout__label--focused .adyen-checkout__label__text{color:#06f}.adyen-checkout__error-text{display:-webkit-box;display:flex;color:#d10244;font-weight:400;margin-top:4px;font-size:.75em;-webkit-box-align:center;align-items:center}
margin-bottom:16px; .adyen-checkout__spinner__wrapper{height:100%;display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;-webkit-box-align:center;align-items:center}.adyen-checkout__spinner__wrapper--inline{height:auto;display:inline-block;margin-right:8px}.adyen-checkout__spinner{border-radius:50%;height:43px;width:43px;border:3px solid #06f;border-top-color:transparent;-webkit-animation:rotateSpinner 1.5s linear infinite;animation:rotateSpinner 1.5s linear infinite}.adyen-checkout__spinner--large{height:43px;width:43px}.adyen-checkout__spinner--small{height:16px;width:16px;border-width:2px}.adyen-checkout__spinner--medium{height:28px;width:28px}@-webkit-keyframes rotateSpinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotateSpinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}
width:100% .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{padding-bottom:0;padding-left:24px;position:relative;display:block;color:inherit;font-size:.81em;font-weight:400;line-height:16px;overflow:visible}.adyen-checkout__label--focused .adyen-checkout__radio_group__label{color:inherit}.adyen-checkout__radio_group__label:before{content:"";position:absolute;background-color:#fff;border:1px solid #b9c4c9;border-radius:50%;height:16px;width:16px;left:0;top:0;-webkit-transition:border-color .2s ease-out,box-shadow .2s ease-out;transition:border-color .2s ease-out,box-shadow .2s ease-out}.adyen-checkout__radio_group__label:hover:before{border-color:#99a3ad;box-shadow:0 0 0 2px #d4d9db;cursor:pointer}.adyen-checkout__radio_group__label:after{content:"";display:block;position:absolute;margin:0 auto;left:5px;top:5px;height:6px;width:6px;background-color:#fff;border-radius:50%;-webkit-transform:scale(0);transform:scale(0);-webkit-transition:-webkit-transform .2s ease-out;transition:-webkit-transform .2s ease-out;transition:transform .2s ease-out;transition:transform .2s ease-out,-webkit-transform .2s ease-out;box-shadow:0 1px 1px rgba(0,15,45,.25)}.adyen-checkout__radio_group__label:hover{border-color:#06f;cursor:pointer}.adyen-checkout__radio_group__input:checked+.adyen-checkout__radio_group__label:before,.adyen-checkout__radio_group__label--selected{background-color:#06f;border:0;-webkit-transition:all .2s ease-out;transition:all .2s 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__input:focus+.adyen-checkout__radio_group__label:before{border-color:#06f;box-shadow:0 0 0 2px rgba(0,102,255,.4)}.adyen-checkout__radio_group__input:checked+.adyen-checkout__radio_group__label:hover:before,.adyen-checkout__radio_group__input:checked:active+.adyen-checkout__radio_group__label:before,.adyen-checkout__radio_group__input:checked:focus+.adyen-checkout__radio_group__label:before{box-shadow:0 0 0 2px rgba(0,102,255,.4)}.adyen-checkout__radio_group__label.adyen-checkout__radio_group__label--invalid:before{border:1px solid #d10244}
} .adyen-checkout__checkbox{display:block}.adyen-checkout__checkbox__label{position:relative;padding-left:24px;cursor:pointer;display:inline-block;line-height:19px;color:#00112c;font-size:.81em;font-weight:400;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.adyen-checkout__checkbox__input{position:absolute;opacity:0;pointer-events:none}.adyen-checkout__checkbox__input:checked+.adyen-checkout__checkbox__label:before{opacity:1}.adyen-checkout__checkbox__input:checked+.adyen-checkout__checkbox__label:after{border:1px solid #06f;background-color:#06f}.adyen-checkout__checkbox__input:checked:hover+.adyen-checkout__checkbox__label:after{box-shadow:0 0 0 2px rgba(0,102,255,.4);border-color:#06f}.adyen-checkout__checkbox__input:focus+.adyen-checkout__checkbox__label:after{border:1px solid #06f;box-shadow:0 0 0 2px #99c2ff}.adyen-checkout__checkbox__input:hover:not(:focus)+.adyen-checkout__checkbox__label:after{border-color:#99a3ad;box-shadow:0 0 0 2px #d4d9db}.adyen-checkout__checkbox__input+.adyen-checkout__checkbox__label:before{border-bottom:1px solid transparent;border-right:1px solid transparent;border-color:transparent #fff #fff transparent;border-style:solid;border-width:1px 2px 2px 1px;border-radius:0 2px 1px 2px;content:"";height:11px;left:1px;opacity:0;position:absolute;top:2px;-webkit-transform:rotate(37deg);transform:rotate(37deg);-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transition:opacity .2s ease-out;transition:opacity .2s ease-out;width:6px;z-index:1}.adyen-checkout__checkbox__input+.adyen-checkout__checkbox__label:after{content:"";position:absolute;top:0;left:0;width:16px;height:16px;border-radius:3px;background-color:#fff;border:1px solid #b9c4c9;z-index:0;-webkit-transition:background .15s ease-out,border .05s ease-out,box-shadow .1s ease-out;transition:background .15s ease-out,border .05s ease-out,box-shadow .1s ease-out}.adyen-checkout__field--consentCheckbox{background:#e6e9eb;border:1px solid #e6e9eb;border-radius:6px;padding:14px 40px 13px 14px}.adyen-checkout__field--consentCheckbox.adyen-checkout__field--error{border-color:#d10244}.adyen-checkout__field--consentCheckbox .adyen-checkout-input__inline-validation{right:-27px;top:10px}
.adyen-checkout__field:last-of-type{ ._2kGp2i5c0AbQ-xsf7RXRPw{position:relative}.waz0IrxZYBVZZIGFHebqH{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;cursor:pointer;-webkit-box-pack:justify;justify-content:space-between}.waz0IrxZYBVZZIGFHebqH:after{position:absolute;content:"";height:6px;right:16px;width:8px;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='8' height='7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.195 6.565a1 1 0 001.6 0l2.992-3.98a1 1 0 00-.8-1.602H1.013a1 1 0 00-.8 1.6l2.983 3.982z' fill='%23687282'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:50%}._1EqeUznxl6cw_k2HT8KvN4:after{-webkit-transform:rotate(180deg);transform:rotate(180deg)}._2UxApCd88Bra9uwR-b2sbD{position:absolute;width:100%;background:#fff;list-style:none;padding:0;z-index:1;margin:0 0 50px;overflow-y:auto;display:none}._2UxApCd88Bra9uwR-b2sbD.Mlt8tYX1JPlpkrnVPe-r8{display:block}._3nIQRo76neVHr0CKuCZHKc{display:-webkit-box;display:flex;-webkit-box-pack:justify;justify-content:space-between;-webkit-box-align:center;align-items:center}
margin-bottom:0 .adyen-checkout__dropdown{max-width:100%;width:100%;font-size:1em}.adyen-checkout__dropdown__button{padding:9px 24px 9px 12px;border:1px solid #b9c4c9;background:#fff;color:#00112c;text-decoration:none;border-radius:6px;outline:0;width:100%;font-size:1em;height:40px;line-height:20px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:border .2s ease-out,box-shadow .2s ease-out;transition:border .2s ease-out,box-shadow .2s ease-out}.adyen-checkout__dropdown__button:hover{border-color:#99a3ad}.adyen-checkout__dropdown__button__icon{margin-right:8px;margin-left:auto;max-width:40px;max-height:26px;border-radius:3px}.adyen-checkout__dropdown__button--active,.adyen-checkout__dropdown__button--active:hover,.adyen-checkout__dropdown__button:active,.adyen-checkout__dropdown__button:focus{border-color:#06f;box-shadow:0 0 0 2px #99c2ff}.adyen-checkout__dropdown__button--readonly,.adyen-checkout__dropdown__button--readonly--active,.adyen-checkout__dropdown__button--readonly:focus,.adyen-checkout__dropdown__button--readonly:hover{background:#e6e9eb;border-color:transparent;color:#00112c;cursor:not-allowed}.adyen-checkout__dropdown__button--readonly:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='8' height='7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.195 6.565a1 1 0 001.6 0l2.992-3.98a1 1 0 00-.8-1.602H1.013a1 1 0 00-.8 1.6l2.983 3.982z' fill='%23B9C4C9'/%3E%3C/svg%3E")}.adyen-checkout__dropdown__button--invalid{border-color:#d10244}.adyen-checkout__dropdown__button__text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.adyen-checkout__dropdown__list{z-index:2;border-radius:6px;max-height:375px;box-shadow:0 2px 7px rgba(0,15,45,.3)}.adyen-checkout__dropdown__list.adyen-checkout__dropdown__list--active{margin-top:2px}.adyen-checkout__dropdown__element{padding:8px;line-height:20px;border:1px solid transparent;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto;cursor:pointer;font-size:.81em;outline:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:background .2s ease-out,border-color .2s ease-out;transition:background .2s ease-out,border-color .2s ease-out}.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:rgba(230,233,235,.6)}.adyen-checkout__dropdown__element.adyen-checkout__dropdown__element--active{background:rgba(0,102,255,.1)}.adyen-checkout__dropdown__element.adyen-checkout__dropdown__element--active:active,.adyen-checkout__dropdown__element.adyen-checkout__dropdown__element--active:focus,.adyen-checkout__dropdown__element.adyen-checkout__dropdown__element--active:hover{background:rgba(0,102,255,.15)}.adyen-checkout__dropdown__element__icon{border-radius:3px;margin-right:8px;max-width:40px;max-height:26px}.adyen-checkout__dropdown+.adyen-checkout-input__inline-validation{right:32px}
} .adyen-checkout__select-list{margin:0;padding:0;background:#fff;border:1px solid #b9c4c9;border-radius:6px;max-height:140px;min-height:100px;min-width:300px;overflow-y:scroll;width:100%}.adyen-checkout__select-list__item{display:inline-block;padding:9px;border:1px solid transparent;border-bottom-color:#e6e9eb;background:#fff;outline:0;width:100%;font-size:1em;cursor:pointer;line-height:20px}.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(230,233,235,.6)}.adyen-checkout__select-list__item--selected{background:rgba(0,102,255,.1);font-weight:500}.adyen-checkout__select-list__item--selected:active,.adyen-checkout__select-list__item--selected:focus,.adyen-checkout__select-list__item--selected:hover{background:rgba(0,102,255,.15)}
.adyen-checkout__label{ .adyen-checkout__field-wrapper{display:-webkit-box;display:flex;width:100%}.adyen-checkout__field--20{width:20%}.adyen-checkout__field--30{width:30%}.adyen-checkout__field--40{width:40%}.adyen-checkout__field--50{width:50%}.adyen-checkout__field--60{width:60%}.adyen-checkout__field--70{width:70%}.adyen-checkout__field--80{width:80%}.adyen-checkout__field--col-70{width:calc(70% - 8px)}.adyen-checkout__field--col-30{width:calc(30% - 8px)}.adyen-checkout__field--col-50{width:calc(50% - 8px)}.adyen-checkout__field-wrapper>.adyen-checkout__field:first-child{margin-right:8px}.adyen-checkout__field-wrapper>.adyen-checkout__field:nth-child(2){margin-left:8px}.adyen-checkout__field-wrapper:last-of-type>.adyen-checkout__field{margin-bottom:0}.adyen-checkout__input{color:#00112c;caret-color:#06f;font-size:1em;font-family:inherit;display:block;height:40px;background:#fff;border:1px solid #b9c4c9;border-radius:6px;padding:5px 8px;position:relative;outline:none;width:100%;-webkit-transition:border .2s ease-out,box-shadow .2s ease-out;transition:border .2s ease-out,box-shadow .2s ease-out}.adyen-checkout__input:hover{border-color:#99a3ad}.adyen-checkout__input:required{box-shadow:none}.adyen-checkout__input--disabled,.adyen-checkout__input[readonly]{background:#e6e9eb;border-color:#e6e9eb}.adyen-checkout__input--disabled:hover{border-color:#e6e9eb}.adyen-checkout__input-wrapper{position:relative;display:block}.adyen-checkout__input-wrapper--block{display:block}.adyen-checkout-input__inline-validation{position:absolute;width:16px;height:16px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);right:14px}.adyen-checkout-input__inline-validation--valid{color:#0abf53}.adyen-checkout-input__inline-validation--invalid{color:#d10244}.adyen-checkout__input--invalid{border-color:#d10244}.adyen-checkout__input--valid{border-bottom-color:#0abf53}.adyen-checkout__input--error,.adyen-checkout__input--error:hover,.adyen-checkout__input--invalid,.adyen-checkout__input--invalid:hover{border-color:#d10244}.adyen-checkout__input::-webkit-input-placeholder{color:#b9c4c9;font-weight:200}.adyen-checkout__input::-moz-placeholder{color:#b9c4c9;font-weight:200}.adyen-checkout__input:-ms-input-placeholder{color:#b9c4c9;font-weight:200}.adyen-checkout__input::-ms-input-placeholder{color:#b9c4c9;font-weight:200}.adyen-checkout__input::placeholder{color:#b9c4c9;font-weight:200}.adyen-checkout__input--date{padding-right:30px}.adyen-checkout__input--focus,.adyen-checkout__input--focus:hover,.adyen-checkout__input:active,.adyen-checkout__input:active:hover,.adyen-checkout__input:focus,.adyen-checkout__input:focus:hover{border:1px solid #06f;box-shadow:0 0 0 2px #99c2ff}.adyen-checkout__input[readonly],.adyen-checkout__input[readonly]:hover{background-color:#e6e9eb;border-color:transparent;color:#687282;cursor:default}
display:block .adyen-checkout__open-invoice .adyen-checkout__field--gender .adyen-checkout__radio_group{display:-webkit-box;display:flex}.adyen-checkout__open-invoice .adyen-checkout__field--gender .adyen-checkout__radio_group>label{margin-right:20px}.adyen-checkout__open-invoice .adyen-checkout__fieldset--billingAddress{padding-bottom:8px}.adyen-checkout__open-invoice .adyen-checkout__fieldset--deliveryAddress{margin-top:24px;padding-bottom:8px}.adyen-checkout__open-invoice .adyen-checkout__input--separateDeliveryAddress{margin-bottom:0}.adyen-checkout__open-invoice .adyen-checkout__radio_group{display:-webkit-box;display:flex;margin:8px 0}.adyen-checkout__open-invoice .adyen-checkout__radio_group__input-wrapper{margin-right:16px}.adyen-checkout__open-invoice .adyen-checkout__radio_group__input-wrapper:last-child{margin:0}.adyen-checkout__open-invoice .adyen-checkout__field--consentCheckbox{margin-top:22px}.adyen-checkout__input--separateDeliveryAddress+.adyen-checkout__checkbox__label{margin-top:16px}
} .adyen-checkout__button{background:#00112c;border:0;border-radius:6px;color:#fff;cursor:pointer;font-size:1em;font-weight:500;height:48px;margin:0;padding:15px;text-decoration:none;-webkit-transition:background .3s ease-out,box-shadow .3s ease-out;transition:background .3s ease-out,box-shadow .3s ease-out;width:100%}.adyen-checkout__button:focus{box-shadow:0 0 0 2px #99c2ff;outline:0}.adyen-checkout__button:hover{background:#1c3045;box-shadow:0 0,0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14)}.adyen-checkout__button:active{background:#3a4a5c}.adyen-checkout__button:hover:focus{box-shadow:0 0 0 2px #99c2ff,0 3px 4px rgba(0,15,45,.2)}.adyen-checkout__button:disabled,.adyen-checkout__button:disabled:hover{box-shadow:none;cursor:not-allowed;opacity:.4;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all}.adyen-checkout__button.adyen-checkout__button--loading{background:#687282;box-shadow:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.adyen-checkout__button.adyen-checkout__button--pay{margin-top:24px}.adyen-checkout__button.adyen-checkout__button--standalone{margin-top:0}.adyen-checkout__button.adyen-checkout__button--inline{display:block;width:auto;height:auto;padding:10px 8px;font-size:.81em}.adyen-checkout__button.adyen-checkout__button--ghost{background:none;border:0;color:#00112c}.adyen-checkout__button.adyen-checkout__button--ghost:hover{background:#f7f8f9;box-shadow:none}.adyen-checkout__button.adyen-checkout__button--ghost:active{background:#e6e9eb;box-shadow:none}.adyen-checkout__button.adyen-checkout__button--secondary{padding:10px 12px;background:rgba(0,102,255,.1);border:1px solid transparent;color:#06f}.adyen-checkout__button.adyen-checkout__button--secondary:hover{background:rgba(0,102,255,.2);box-shadow:none}.adyen-checkout__button.adyen-checkout__button--secondary:active,.adyen-checkout__button.adyen-checkout__button--secondary:active:hover{background:rgba(0,102,255,.3);box-shadow:none}.adyen-checkout__button.adyen-checkout__button--link{background:transparent;border:1px solid transparent;color:#06f;font-weight:400;border-radius:3px;padding:2px}.adyen-checkout__button.adyen-checkout__button--link:hover{background:transparent;text-decoration:underline;box-shadow:none}.adyen-checkout__button.adyen-checkout__button--completed,.adyen-checkout__button.adyen-checkout__button--completed:active,.adyen-checkout__button.adyen-checkout__button--completed:active:hover,.adyen-checkout__button.adyen-checkout__button--completed:hover{background:#0abf53;color:#fff}.adyen-checkout__button.adyen-checkout__button--completed .adyen-checkout__button__icon{-webkit-filter:brightness(0) invert(1);filter:brightness(0) invert(1)}.adyen-checkout__button__content{height:100%;-webkit-box-align:center;align-items:center;display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center}.adyen-checkout__button__icon{margin-right:12px}.adyen-checkout__button__text{display:block;-webkit-box-pack:center;justify-content:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.adyen-checkout__button .adyen-checkout__spinner{border-color:transparent #fff #fff}
.adyen-checkout__helper-text,.adyen-checkout__label__text{ @supports (-webkit-appearance:-apple-pay-button){._26P3-497Bo_kcWzSC3HwGB{display:inline-block;-webkit-appearance:-apple-pay-button;cursor:pointer}._3Ml54cUbtBzCVkvsUVCz2j{-apple-pay-button-style:#000}._1qE8Ax1p0lKQo48G-CCVqZ{-apple-pay-button-style:#fff}.j9FE548KYNuE6WmBWaiNC{-apple-pay-button-style:white-outline}._2mnnXXIeaYr6ejFqAw5LVo{-apple-pay-button-type:plain}.eMnIyuX5G0zZyai40-cM_{-apple-pay-button-type:buy}._3zvI8car845xrwaqzFfO2W{-apple-pay-button-type:donate}.ipg0J6WFnN7o8UJJFmC4s{-apple-pay-button-type:check-out}._155XskC0jg67fCvlP3APVl{-apple-pay-button-type:book}._3uPJ53ZiJwUi1Ccq9H4PsZ{-apple-pay-button-type:subscribe}}@supports not (-webkit-appearance:-apple-pay-button){._26P3-497Bo_kcWzSC3HwGB{display:inline-block;background-size:100% 60%;background-repeat:no-repeat;background-position:50% 50%;border-radius:5px;padding:0;box-sizing:border-box;min-width:200px;min-height:32px;max-height:64px}._3Ml54cUbtBzCVkvsUVCz2j{background-image:-webkit-named-image(apple-pay-logo-white);background-color:#000}._1qE8Ax1p0lKQo48G-CCVqZ,.j9FE548KYNuE6WmBWaiNC{background-image:-webkit-named-image(apple-pay-logo-black);background-color:#fff}.j9FE548KYNuE6WmBWaiNC{border:.5px solid #000}}
color:#00112c; .adyen-checkout__applepay__button{width:240px;height:40px}.adyen-checkout__dropin .adyen-checkout__applepay__button{width:100%}
display:block; .adyen-checkout__field--issuer-list{margin-bottom:0}
font-size:.81em; ._2tAzuCpLXISBbB0i1w8DVZ{position:relative}._2tAzuCpLXISBbB0i1w8DVZ *,._2tAzuCpLXISBbB0i1w8DVZ :after,._2tAzuCpLXISBbB0i1w8DVZ :before{box-sizing:border-box}._2Iaf5OCcFDHNbg4xIfIudh{border-radius:3px;position:absolute;right:10px;margin-left:7px;-webkit-transform:translateY(-50%);transform:translateY(-50%);top:50%;height:18px;width:27px}._2Ij_ndRDnCol2zr5QeQTDc{opacity:1}._1wHzqkXPXckZF1L7O0lJcl{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;display:none}._1DzoelWVqVVxPpbFf_P8CW{display:block}._3zh3YASnApBoXd9ZdXmHBz{opacity:0}._3JmldYKADXTctIE9oP8lcu{display:block;max-height:100px}._1Z1lpTOoiszbauxOoGwrWf{display:none}
font-weight:400; ._1jpVsksYS5faJOp2y0Tpl4{opacity:1}._3LDWzlGXC0eWQ4YCw4-qjD{opacity:0}._3eCyK2bUQJ0swg0UM0nnQN{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;display:none}._3UDtXj7dWSJxI8TptPZ6N2{display:block}
line-height:13px; .adyen-checkout__card-input__form{-webkit-transition:opacity .25s ease-out;transition:opacity .25s ease-out}.adyen-checkout__card__cardNumber{max-width:400px}.adyen-checkout__card__cardNumber__input{padding:5px 8px}.adyen-checkout__card__exp-date__input--oneclick{line-height:30px;font-weight:400;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.adyen-checkout__card__holderName,.adyen-checkout__field--expiryDate,.adyen-checkout__field--storedCard{margin-bottom:0}.adyen-checkout__card__holderName,.adyen-checkout__card__kcp-authentication,.adyen-checkout__installments,.adyen-checkout__store-details{margin-top:16px}.adyen-checkout__field--cardNumber .adyen-checkout__input--error .adyen-checkout__card__cardNumber__brandIcon{display:none}.adyen-checkout__field--cardNumber .adyen-checkout__input--valid:not(.adyen-checkout__card__cardNumber__input--noBrand)+.adyen-checkout-input__inline-validation--valid{display:none}.adyen-checkout__card-input .adyen-checkout__fieldset--address{margin-top:16px}.adyen-checkout__field--securityCode.adyen-checkout__field--error .adyen-checkout__card__cvc__hint,.adyen-checkout__field--securityCode.adyen-checkout__field--valid .adyen-checkout__card__cvc__hint{opacity:0}@-webkit-keyframes cvcIndicateLocation{0%{opacity:1}to{opacity:.3}}@keyframes cvcIndicateLocation{0%{opacity:1}to{opacity:.3}}.adyen-checkout__label--focused .adyen-checkout__card__cvc__hint__location{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-name:cvcIndicateLocation;animation-name:cvcIndicateLocation;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-direction:alternate;animation-direction:alternate}.adyen-checkout__card__cvc__hint__wrapper{position:absolute;right:0;top:0;height:100%;width:27px;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;margin:0 10px;-webkit-transition:-webkit-transform .3s cubic-bezier(.455,.03,.515,.955);transition:-webkit-transform .3s cubic-bezier(.455,.03,.515,.955);transition:transform .3s cubic-bezier(.455,.03,.515,.955);transition:transform .3s cubic-bezier(.455,.03,.515,.955),-webkit-transform .3s cubic-bezier(.455,.03,.515,.955);-webkit-transform-origin:center;transform-origin:center;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;will-change:transform;-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-transform:translateZ(0);transform:translateZ(0)}.adyen-checkout__field__cvc--front-hint.adyen-checkout__card__cvc__hint__wrapper{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}.adyen-checkout__card__cvc__hint{-webkit-backface-visibility:hidden;backface-visibility:hidden;position:absolute;-webkit-transition:opacity .1s linear;transition:opacity .1s linear}.adyen-checkout__card__cvc__hint--front{-webkit-transform:rotateY(180deg);transform:rotateY(180deg)}@media (prefers-reduced-motion:reduce){.adyen-checkout__card__cvc__hint__wrapper{-webkit-transition:none;transition:none}}
padding-bottom:5px .adyen-checkout__image{opacity:0;-webkit-transition:opacity .6s ease-out;transition:opacity .6s ease-out}.adyen-checkout__image--loaded{opacity:1}
} .adyen-checkout__button-group{background:transparent;display:-webkit-box;display:flex;-webkit-box-pack:justify;justify-content:space-between}.adyen-checkout__button-group .adyen-checkout__button{background:transparent;border:0;box-shadow:inset 0 0 0 1px #99a3ad;color:#00112c;font-size:.81em;font-weight:400;line-height:40px;margin-right:8px;height:40px;padding:0;text-align:center}.adyen-checkout__button-group .adyen-checkout__button:last-child{margin-right:0}.adyen-checkout__button-group .adyen-checkout__button:hover{background:transparent;box-shadow:inset 0 0 0 2px #99a3ad}.adyen-checkout__button-group .adyen-checkout__button:active{background:#f7f8f9;box-shadow:inset 0 0 0 2px #99a3ad}.adyen-checkout__button-group .adyen-checkout__button--disabled,.adyen-checkout__button-group .adyen-checkout__button--disabled:hover{cursor:not-allowed;opacity:.4;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.adyen-checkout__button-group .adyen-checkout__button--selected,.adyen-checkout__button-group .adyen-checkout__button--selected:active,.adyen-checkout__button-group .adyen-checkout__button--selected:active:hover,.adyen-checkout__button-group .adyen-checkout__button--selected:hover{background:#e5efff;box-shadow:inset 0 0 0 2px #06f;color:#06f;font-weight:500;height:40px;-webkit-transition:none;transition:none}.adyen-checkout__button-group .adyen-checkout__button .adyen-checkout__button-group__input{opacity:0;pointer-events:none;position:absolute}
.adyen-checkout__helper-text{ .adyen-checkout__adyen-giving .adyen-checkout__status__icon{display:block;margin:56px auto 32px}.adyen-checkout__adyen-giving .adyen-checkout__status__text{color:#00112c;margin-bottom:56px;text-align:center}.adyen-checkout__campaign{border-radius:6px;background:#00112c;height:227px;overflow:hidden;position:relative}.adyen-checkout__campaign-link:hover .adyen-checkout__campaign-description{text-decoration:underline}.adyen-checkout__campaign-container{height:100%}.adyen-checkout__campaign-logo{border:2px solid hsla(0,0%,100%,.4);border-radius:3px;display:block;height:48px;margin-bottom:16px;overflow:hidden;width:48px}.adyen-checkout__campaign-background-image{background-color:#00112c;background-position:50%;background-size:cover;height:100%}.adyen-checkout__campaign-link .adyen-checkout__campaign-background-image:before{background:inherit;content:"";height:100%;position:absolute;-webkit-transition:-webkit-transform .6s ease-out;transition:-webkit-transform .6s ease-out;transition:transform .6s ease-out;transition:transform .6s ease-out,-webkit-transform .6s ease-out;width:100%}.adyen-checkout__campaign-link .adyen-checkout__campaign-background-image:hover:before{-webkit-transform:scale(1.1);transform:scale(1.1)}.adyen-checkout__campaign-link .adyen-checkout__campaign-content{pointer-events:none}.adyen-checkout__campaign-content{bottom:0;padding:16px;position:absolute;z-index:2}.adyen-checkout__campaign-description,.adyen-checkout__campaign-title{color:#fff;font-weight:400;margin:0}.adyen-checkout__campaign-title{font-size:1em;margin-bottom:8px}.adyen-checkout__campaign-description{font-size:.81em;line-height:19px}.adyen-checkout__adyen-giving-actions{margin-top:16px}.adyen-checkout__button.adyen-checkout__button--donate{margin:16px auto 8px}.adyen-checkout__button.adyen-checkout__button--decline{display:block;margin:auto;width:auto}
color:#687282 .adyen-checkout__paywithgoogle .gpay-button.long{width:100%;padding:15px 24px 13px;height:48px;-webkit-transition:background-color .3s ease-out,box-shadow .3s ease-out;transition:background-color .3s ease-out,box-shadow .3s ease-out}.adyen-checkout__paywithgoogle .gpay-button.long:focus{box-shadow:0 0 0 2px #99c2ff;outline:0}
} .adyen-checkout__econtext-input__field{display:-webkit-box;display:flex;flex-wrap:wrap}.adyen-checkout__econtext-input__field .adyen-checkout__field--firstName,.adyen-checkout__econtext-input__field .adyen-checkout__field--lastName{width:calc(50% - 8px);min-width:250px;max-width:100%}.adyen-checkout__econtext-input__field .adyen-checkout__field--firstName{margin-right:16px}
.adyen-checkout__label__text{ .adyen-checkout__voucher-result{box-sizing:border-box;border-radius:12px;text-align:center;position:relative}.adyen-checkout__voucher-result__bottom,.adyen-checkout__voucher-result__top{background:#fff;border:1px solid #d4d9db}.adyen-checkout__voucher-result__top{padding:40px 0 24px;border-radius:12px 12px 0 0;border-bottom:0}.adyen-checkout__voucher-result__bottom{border-top:0;border-radius:0 0 12px 12px}.adyen-checkout__voucher-result__separator{background:#fff;position:relative;width:calc(100% - 14px);height:13px;margin:0 auto;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.adyen-checkout__voucher-result__separator:after,.adyen-checkout__voucher-result__separator:before{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNyIgaGVpZ2h0PSIxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBjbGlwLXBhdGg9InVybCgjY2xpcDApIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTAgMGw1IDIgMS41IDRIN1YwSDB6bTAgMTNsNS0yIDEuNS00SDd2NkgweiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik02LjQyMyA2LjVDNi40MjMgMy4zMTIgMy43ODMuNzU2LjUuNTE4djBjMy4zODYuMjM2IDYgMi44NTUgNiA1Ljk4MiAwIDMuMTI3LTIuNjE0IDUuNzQ2LTYgNS45ODN2LS4wMDFjMy4yODQtLjIzNyA1LjkyMy0yLjc5NCA1LjkyMy01Ljk4MnoiIHN0cm9rZT0iI0Q0RDlEQiIvPjxwYXRoIGZpbGw9IiNENEQ5REIiIGQ9Ik0wIDBoMXYxSDB6TTAgMTJoMXYxSDB6Ii8+PC9nPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0wIDBoN3YxM0gweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==)}.adyen-checkout__voucher-result__separator:before{background-position:100%;background-repeat:no-repeat;content:"";left:-7px;top:0;position:absolute;width:7px;height:13px}.adyen-checkout__voucher-result__separator:after{background-position:100%;background-repeat:no-repeat;content:"";right:-7px;top:0;position:absolute;width:7px;height:13px;-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.adyen-checkout__voucher-result__separator__inner{width:100%;border-top:1px solid #e6e9eb}.adyen-checkout__voucher-result__image{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;width:100%;margin-bottom:40px}.adyen-checkout__voucher-result__image__wrapper{display:block;position:relative;height:48px;margin:0 24px}.adyen-checkout__voucher-result__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__voucher-result__image__wrapper:nth-child(2):before{border-left:1px solid #d4d9db;content:"";height:64px;left:-24.5px;position:absolute;top:-8px;width:1px}.adyen-checkout__voucher-result__image__brand,.adyen-checkout__voucher-result__image__issuer{height:48px;border-radius:3px}.adyen-checkout__voucher-result__introduction{line-height:19px;font-size:.81em;text-align:center;color:#00112c;max-width:400px;margin:0 auto}.adyen-checkout__voucher-result__amount{margin:24px auto 0;font-size:1em;color:#00112c;text-align:center;font-weight:700}.adyen-checkout__voucher-result__surcharge{font-size:.81em;line-height:19px;text-align:center;color:#687282;display:block;font-weight:400}.adyen-checkout__voucher-result__code__label{position:absolute;display:block;font-weight:400;right:0;left:0;width:auto;line-height:19px;top:-2px;margin:0 auto;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.adyen-checkout__voucher-result__code__label:before{content:"";position:absolute}.adyen-checkout__voucher-result__code__label__text{font-size:13px;color:#00112c;background:#fff;padding:0 8px;letter-spacing:normal;line-height:1}.adyen-checkout__voucher-result__code__barcode{display:block;margin:0 auto 8px;max-width:100%;height:56px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.adyen-checkout__voucher-result__code{position:relative;font-size:1.5em;text-align:center;letter-spacing:1px;color:#00112c;border-width:1px 0;padding:16px 48px;display:inline-block;margin:0 auto;width:100%;font-weight:700;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all;word-break:break-word;line-height:1.2}.adyen-checkout__voucher-result__details{list-style:none;padding:0;margin:-1px auto 0}.adyen-checkout__voucher-result__details__item{display:-webkit-box;display:flex;-webkit-box-pack:justify;justify-content:space-between;font-size:.81em;color:#00112c;padding:16px 24px;border-top:1px solid #e6e9eb;word-break:break-word}.adyen-checkout__voucher-result__details__item:last-child{margin-bottom:0}.adyen-checkout__voucher-result__details__label{max-width:50%;text-align:left}.adyen-checkout__voucher-result__details__value{max-width:50%;text-align:right;font-weight:700}.adyen-checkout__voucher-result__actions{margin:0 auto 32px;max-width:100%;min-width:200px;width:300px;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;list-style:none;padding:0}.adyen-checkout__voucher-result__actions__item{margin:0 4px}
display:block; .adyen-checkout__paypal__button{display:-webkit-box;display:flex;margin-bottom:16px}.adyen-checkout__paypal__button:empty{display:none}.adyen-checkout__paypal__status--pending{margin:16px 0}.adyen-checkout__paypal__status--processing{-webkit-box-align:center;align-items:center;display:-webkit-box;display:flex;font-size:13px;-webkit-box-pack:center;justify-content:center;padding:24px 0}.adyen-checkout__payment-method .adyen-checkout__paypal__status--pending{margin:-16px 0 38px}.adyen-checkout__payment-method .adyen-checkout__paypal__status--processing{padding:20px 0 65px}
overflow:hidden; .adyen-checkout__iban-input__number{text-transform:uppercase;padding:5px 36px 5px 8px}
text-overflow:ellipsis; .adyen-checkout__threeds2__challenge,.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__threeds2__challenge.adyen-checkout__threeds2__challenge--05{position:relative;overflow:hidden;padding-top:56.25%}.adyen-checkout__threeds2__challenge.adyen-checkout__threeds2__challenge--05 .adyen-checkout__iframe--threeDSIframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0}
transition:color .1s ease-out; .adyen-checkout__qr-loader{background:#fff;padding:40px;border:1px solid #d4d9db;border-radius:12px;text-align:center}.adyen-checkout__qr-loader--result{padding:100px}.adyen-checkout__qr-loader--app{border:0;border-radius:0;padding:0}.adyen-checkout__qr-loader__brand-logo{width:74px;border-radius:3px}.adyen-checkout__qr-loader__subtitle{margin-top:32px}.adyen-checkout__qr-loader__subtitle--result{margin-bottom:32px}.adyen-checkout__qr-loader__payment_amount,.adyen-checkout__qr-loader__subtitle{color:#00112c;font-size:1em;line-height:19px}.adyen-checkout__qr-loader__icon{width:88px;height:88px}.adyen-checkout__qr-loader__payment_amount{font-weight:700}.adyen-checkout__qr-loader__progress{height:4px;background:#d4d9db;border-radius:24px;margin:32px auto 12px;width:152px;padding-right:3%}.adyen-checkout__qr-loader__percentage{display:block;height:100%;border-radius:24px;background:#06f}.adyen-checkout__qr-loader__countdown{color:#687282;font-size:.81em}.adyen-checkout__qr-loader>.adyen-checkout__spinner__wrapper{margin:60px 0}.adyen-checkout__qr-loader__app-link{margin-top:16px;display:none}.adyen-checkout__qr-loader__separator__label{position:relative;font-size:13px;color:#687282;overflow:hidden;text-align:center;z-index:1;display:block}.adyen-checkout__qr-loader__separator__label:after,.adyen-checkout__qr-loader__separator__label:before{position:absolute;top:51%;overflow:hidden;width:50%;height:1px;content:"\A0";background-color:#e6e9eb}.adyen-checkout__qr-loader__separator__label:before{margin-left:-52%;text-align:right}.adyen-checkout__qr-loader__separator__label:after{margin-left:2%}.adyen-checkout__button.adyen-checkout__button--qr-loader{text-decoration:none;margin-top:24px}@media only screen and (max-device-width:1200px){.adyen-checkout__qr-loader__app-link{display:block}}
white-space:nowrap .adyen-checkout__doku-input__field{display:-webkit-box;display:flex;flex-wrap:wrap}.adyen-checkout__doku-input__field .adyen-checkout__field--firstName,.adyen-checkout__doku-input__field .adyen-checkout__field--lastName{width:calc(50% - 8px);min-width:250px;max-width:100%}.adyen-checkout__doku-input__field .adyen-checkout__field--firstName{margin-right:16px}
} .adyen-checkout__voucher-result--boletobancario .adyen-checkout__voucher-result__code{font-size:.81em;line-height:19px;word-break:break-all;padding:24px}
.adyen-checkout__label__text--error{ .adyen-checkout__voucher-result--oxxo .adyen-checkout__voucher-result__code{font-size:.81em;line-height:19px;word-break:break-all;padding:24px}
color:#d10244 .adyen-checkout__giftcard-result{position:relative;background:#fff;border:1px solid #e6e9eb;width:100%;padding:16px;margin-bottom:8px;border-radius:12px}.adyen-checkout__giftcard-result__header{flex-wrap:nowrap;font-size:1em;font-weight:400;-webkit-box-pack:justify;justify-content:space-between;position:relative;width:100%}.adyen-checkout__giftcard-result__header,.adyen-checkout__giftcard-result__header__title{-webkit-box-align:center;align-items:center;display:-webkit-box;display:flex}.adyen-checkout__giftcard-result__name{margin-left:8px}.adyen-checkout__giftcard-result__balance{padding:0;list-style:none;margin:16px 0 0}.adyen-checkout__giftcard-result__balance__item{display:-webkit-box;display:flex;-webkit-box-pack:justify;justify-content:space-between;margin-bottom:8px}.adyen-checkout__giftcard-result__balance__item:last-child{margin-bottom:0}.adyen-checkout__giftcard-result__balance__item--remaining-balance{font-size:.81em}.adyen-checkout__giftcard-result__balance__value--amount{font-weight:700}
} ._2T9kQExpijVM_P8ZmbWqAT{list-style:none;margin:0;padding:0}._2ZCloBYWlRv9GTkR9J7a0_{display:block;max-height:60px}._2_jFPDCxgbayWBQMKR2rMi{display:none}.Fg2uwnDU3lpWzjoffGQq{width:40px;height:26px}.pTTKrAW94J1fqrzM_--G3{margin-right:8px}._1zXEAefSOOUzgA_cpgWdSX{max-height:100%}._1zXEAefSOOUzgA_cpgWdSX ._2_jFPDCxgbayWBQMKR2rMi{display:block}
.adyen-checkout__label--focused .adyen-checkout__label__text{ .adyen-checkout__payment-method__disable-confirmation{background:#d10244;font-size:.81em;color:#fff;border-right:1px solid #c70241;border-left:1px solid #c70241;overflow:hidden;opacity:0;margin:0 -17px;max-height:0;-webkit-transition:opacity .15s ease-out,max-height .15s linear,margin-bottom .1s linear;transition:opacity .15s ease-out,max-height .15s linear,margin-bottom .1s linear}.adyen-checkout__payment-method__disable-confirmation.adyen-checkout__payment-method__disable-confirmation--open{max-height:62px;opacity:1;margin-bottom:16px}.adyen-checkout__payment-method__disable-confirmation__content{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:justify;justify-content:space-between;padding:8px 16px}.adyen-checkout__payment-method__disable-confirmation__buttons{display:-webkit-box;display:flex}.adyen-checkout__payment-method__disable-confirmation__button{background:#d10244;border:1px solid transparent;border-radius:6px;color:#fff;cursor:pointer;display:block;height:auto;line-height:14px;margin:0 0 0 8px;padding:8px;width:auto}.adyen-checkout__payment-method__disable-confirmation__button:hover,.adyen-checkout__payment-method__disable-confirmation__button:hover:focus{box-shadow:none;background:#b8023c}.adyen-checkout__payment-method__disable-confirmation__button:active,.adyen-checkout__payment-method__disable-confirmation__button:hover:active{background:#9e0234;box-shadow:none}.adyen-checkout__payment-method__disable-confirmation__button--remove,.adyen-checkout__payment-method__disable-confirmation__button--remove:disabled{border-color:#fff}.adyen-checkout__payment-method__disable-confirmation__button--cancel,.adyen-checkout__payment-method__disable-confirmation__button--cancel:disabled{border-color:transparent}
color:#06f .adyen-checkout__payment-method{position:relative;background:#fff;border:1px solid #e6e9eb;cursor:pointer;margin-top:-1px;width:100%;-webkit-transition:opacity .3s ease-out;transition:opacity .3s ease-out}.adyen-checkout__payment-method:focus{outline:0}.adyen-checkout__payment-method--selected+.adyen-checkout__payment-method,.adyen-checkout__payment-method:first-child{margin-top:0;border-top-left-radius:12px;border-top-right-radius:12px}.adyen-checkout__payment-method--next-selected,.adyen-checkout__payment-method:last-child{margin-bottom:0;border-bottom-left-radius:12px;border-bottom-right-radius:12px}.adyen-checkout__payment-method--loading{opacity:.2}.adyen-checkout__payment-method--selected.adyen-checkout__payment-method--loading{opacity:.9}.adyen-checkout__payment-method--confirming .adyen-checkout__payment-method__details__content,.adyen-checkout__payment-method--disabling{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.adyen-checkout__payment-method--disabling{opacity:.3}.adyen-checkout__payment-method__header{-webkit-box-align:center;align-items:center;color:#00112c;display:-webkit-box;display:flex;flex-wrap:nowrap;-webkit-box-pack:justify;justify-content:space-between;font-weight:400;font-size:1em;padding:16px 16px 16px 48px;position:relative;-webkit-transition:background .1s ease-out;transition:background .1s ease-out;width:100%}.adyen-checkout__payment-method--standalone .adyen-checkout__payment-method__header{padding:16px}.adyen-checkout__payment-method__header__title{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;flex-shrink:0;margin-right:16px;max-width:100%}.adyen-checkout__payment-method__surcharge{color:#687282;margin-left:5px}.adyen-checkout__payment-method--selected{-webkit-transition:margin .15s cubic-bezier(.4,0,.2,1) 0ms,opacity .3s ease-out;transition:margin .15s cubic-bezier(.4,0,.2,1) 0ms,opacity .3s ease-out;background:#f7f8f9;border:1px solid #e6e9eb;margin:8px 0;border-radius:12px;cursor:default}.adyen-checkout__payment-method--selected .adyen-checkout__payment-method__header{flex-wrap:wrap}.adyen-checkout__payment-method__name{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.adyen-checkout__payment-method__name--selected{font-weight:500}.adyen-checkout__payment-method__details{padding:0 16px;position:relative}.adyen-checkout__payment-method__details__content{margin:0 0 16px}.adyen-checkout__payment-method__image__wrapper{height:26px;width:40px;position:relative}.adyen-checkout__payment-method__image__wrapper:after{content:"";position:absolute;top:0;width:100%;height:100%;left:0;border-radius:3px;border:1px solid rgba(0,27,43,.17)}.adyen-checkout__payment-method__image{display:block;border-radius:3px}.adyen-checkout__payment-method__brands{display:-webkit-box;display:flex;flex-wrap:wrap;margin:4px 0;height:16px;flex-basis:auto;flex-shrink:1;text-align:right;overflow:hidden}.adyen-checkout__payment-method--selected .adyen-checkout__payment-method__brands{text-align:left;overflow:visible;height:auto}.adyen-checkout__payment-method__brands .adyen-checkout__payment-method__image__wrapper{display:inline-block;margin-right:4px;height:16px;width:24px;-webkit-transition:opacity .2s ease-out;transition:opacity .2s ease-out}.adyen-checkout__payment-method__brands .adyen-checkout__payment-method__image__wrapper:last-child{margin:0}.adyen-checkout__payment-method--selected .adyen-checkout__payment-method__brands .adyen-checkout__payment-method__image__wrapper{margin-bottom:4px}.adyen-checkout__payment-method__brands img{width:24px;height:16px}.adyen-checkout__payment-method__image__wrapper--disabled{opacity:.25}.adyen-checkout__payment-method__radio{position:absolute;background-color:#fff;border:1px solid #b9c4c9;border-radius:50%;height:16px;width:16px;left:16px;-webkit-transition:border-color .2s ease-out,box-shadow .2s ease-out;transition:border-color .2s ease-out,box-shadow .2s ease-out}.adyen-checkout__payment-method--standalone .adyen-checkout__payment-method__radio{display:none}.adyen-checkout__payment-method__radio:after{content:"";display:block;position:absolute;margin:0 auto;left:0;right:0;top:50%;height:6px;width:6px;background-color:#fff;border-radius:50%;-webkit-transform:translateY(-50%) scale(0);transform:translateY(-50%) scale(0);-webkit-transition:-webkit-transform .3s ease-out;transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out}.adyen-checkout__payment-method:hover:not(.adyen-checkout__payment-method--selected) .adyen-checkout__payment-method__radio{border-color:#99a3ad;box-shadow:0 0 0 2px #d4d9db;cursor:pointer}.adyen-checkout__payment-method__radio--selected{background-color:#06f;border:0;-webkit-transition:all .3s ease-out;transition:all .3s ease-out}.adyen-checkout__payment-method__radio--selected:hover{box-shadow:0 0 0 2px rgba(0,102,255,.4)}.adyen-checkout__payment-method__radio--selected:after{-webkit-transform:translateY(-50%) scale(1);transform:translateY(-50%) scale(1)}
} .adyen-checkout__status{display:-webkit-box;display:flex;text-align:center;-webkit-box-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;-webkit-box-pack:center;justify-content:center;height:350px;margin:0;padding:32px;background-color:#fff;border-radius:6px;border:1px solid #d4d9db;font-size:1em;color:#00112c}.adyen-checkout__status__icon{margin-bottom:24px}.adyen-checkout__status .adyen-checkout__spinner__wrapper{max-height:88px}
.adyen-checkout__error-text{ .adyen-checkout__dropin,.adyen-checkout__dropin *,.adyen-checkout__dropin :after,.adyen-checkout__dropin :before{box-sizing:border-box}.adyen-checkout__payment-methods-list--loading{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}.adyen-checkout__link{color:#06f;text-decoration:none}.adyen-checkout__link:hover{text-decoration:underline}
align-items:center; ._1V7mk6_fpUl6IOE-QqH-JR{position:relative}._1V7mk6_fpUl6IOE-QqH-JR *,._1V7mk6_fpUl6IOE-QqH-JR :after,._1V7mk6_fpUl6IOE-QqH-JR :before{box-sizing:border-box}._1SeSlzVXGcIdgO40pvhfro{display:block;max-height:100px}
color:#d10244; .adyen-checkout__loading-input__form{-webkit-transition:opacity .25s ease-out;transition:opacity .25s ease-out}.adyen-checkout__pm__holderName{margin-bottom:0}.adyen-checkout__ach-input .adyen-checkout__fieldset--address,.adyen-checkout__ach-sf__form{margin-top:16px}
display:flex; ._1K_z0mRj6YvwYsYK1dJ2r2{display:block;max-height:100px}
font-size:.75em; .adyen-checkout__loading-input__form{-webkit-transition:opacity .25s ease-out;transition:opacity .25s ease-out}
font-weight:400; .adyen-checkout__await{background:#fff;padding:40px;border:1px solid #d4d9db;border-radius:12px;text-align:center}.adyen-checkout__await--result{padding:100px}.adyen-checkout__qr-loader--app{border:0;border-radius:0;padding:0}.adyen-checkout__await__brand-logo{width:74px;border-radius:3px}.adyen-checkout__await__indicator-text,.adyen-checkout__await__subtitle{color:#00112c;font-size:1em;line-height:19px;margin-top:32px}.adyen-checkout__await__indicator-holder .adyen-checkout__await__indicator-text{margin-top:6px;margin-left:10px}.adyen-checkout__await__indicator-holder{display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;margin-top:32px;margin-bottom:20px}.adyen-checkout__await__subtitle--result{margin-bottom:32px}.adyen-checkout__await__icon{width:88px;height:88px}.adyen-checkout__await__progress{height:4px;background:#d4d9db;border-radius:24px;margin:32px auto 12px;width:152px}.adyen-checkout__await__percentage{display:block;height:100%;border-radius:24px;background:#06f}.adyen-checkout__await__countdown{color:#687282;font-size:.81em}.adyen-checkout__await>.adyen-checkout__spinner__wrapper{margin:60px 0}.adyen-checkout__qr-loader__app-link{margin-top:16px;display:none}.adyen-checkout__qr-loader__separator__label{position:relative;font-size:13px;color:#687282;overflow:hidden;text-align:center;z-index:1;display:block}.adyen-checkout__qr-loader__separator__label:after,.adyen-checkout__qr-loader__separator__label:before{position:absolute;top:51%;overflow:hidden;width:50%;height:1px;content:"\A0";background-color:#e6e9eb}.adyen-checkout__qr-loader__separator__label:before{margin-left:-52%;text-align:right}.adyen-checkout__qr-loader__separator__label:after{margin-left:2%}@media only screen and (max-device-width:1200px){.adyen-checkout__qr-loader__app-link{display:block}}
margin-top:4px
}
.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 1.5s infinite linear;
animation:rotateSpinner 1.5s infinite linear;
border:3px solid #06f;
border-radius:50%;
border-top-color:transparent;
height:43px;
width:43px
}
.adyen-checkout__spinner--large{
height:43px;
width:43px
}
.adyen-checkout__spinner--small{
border-width:2px;
height:16px;
width:16px
}
.adyen-checkout__spinner--medium{
height:28px;
width:28px
}
@-webkit-keyframes rotateSpinner{
0%{
-webkit-transform:rotate(0deg);
transform:rotate(0deg)
}
to{
-webkit-transform:rotate(1turn);
transform:rotate(1turn)
}
}
@keyframes rotateSpinner{
0%{
-webkit-transform:rotate(0deg);
transform:rotate(0deg)
}
to{
-webkit-transform:rotate(1turn);
transform:rotate(1turn)
}
}
.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{
color:inherit;
display:block;
font-size:.81em;
font-weight:400;
line-height:16px;
margin-bottom:8px;
overflow:visible;
padding-bottom:0;
padding-left:24px;
position:relative
}
.adyen-checkout__label--focused .adyen-checkout__radio_group__label{
color:inherit
}
.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 .2s ease-out,box-shadow .2s ease-out;
width:16px
}
.adyen-checkout__radio_group__label:hover:before{
border-color:#99a3ad;
box-shadow:0 0 0 2px #d4d9db;
cursor:pointer
}
.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 .2s ease-out;
transition:transform .2s ease-out;
transition:transform .2s ease-out,-webkit-transform .2s ease-out;
width:6px
}
.adyen-checkout__radio_group__label:hover{
border-color:#06f;
cursor:pointer
}
.adyen-checkout__radio_group__input:checked+.adyen-checkout__radio_group__label:before,.adyen-checkout__radio_group__label--selected{
background-color:#06f;
border:0;
transition:all .2s 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__input:checked+.adyen-checkout__radio_group__label:hover:before,.adyen-checkout__radio_group__input:checked:active+.adyen-checkout__radio_group__label:before,.adyen-checkout__radio_group__input:checked:focus+.adyen-checkout__radio_group__label:before{
box-shadow:0 0 0 2px rgba(0,102,255,.4)
}
.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{
opacity:0;
pointer-events:none;
position:absolute
}
.adyen-checkout__checkbox__label{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
color:#00112c;
cursor:pointer;
display:inline-block;
font-size:.81em;
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--invalid+.adyen-checkout__checkbox__label:after{
border:1px solid #d10244
}
.adyen-checkout__checkbox__input:checked+.adyen-checkout__checkbox__label:after{
background-color:#06f;
border:1px solid #06f
}
.adyen-checkout__checkbox__input:hover:not(:focus)+.adyen-checkout__checkbox__label:after{
border-color:#99a3ad;
box-shadow:0 0 0 2px #d4d9db
}
.adyen-checkout__checkbox__input:checked:hover+.adyen-checkout__checkbox__label:after{
border-color:#06f;
box-shadow:0 0 0 2px rgba(0,102,255,.4)
}
.adyen-checkout__checkbox__input:focus+span:after{
border:1px solid #06f;
box-shadow:0 0 0 2px #99c2ff
}
.adyen-checkout__dropdown{
font-size:1em;
max-width:100%;
width:100%
}
.adyen-checkout__dropdown__button{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
background:#fff;
border:1px solid #b9c4c9;
border-radius:6px;
font-size:1em;
height:40px;
line-height:20px;
outline:0;
padding:9px 24px 9px 12px;
transition:border .2s ease-out,box-shadow .2s ease-out;
user-select:none;
width:100%
}
.adyen-checkout__dropdown__button__icon{
margin-right:8px;
max-height:26px;
max-width:40px
}
.adyen-checkout__dropdown__button--active,.adyen-checkout__dropdown__button:active,.adyen-checkout__dropdown__button:focus{
border-color:#06f;
box-shadow:0 0 0 2px #99c2ff
}
.adyen-checkout__dropdown__button--readonly,.adyen-checkout__dropdown__button--readonly.adyen-checkout__dropdown__button--active{
background:#e6e9eb;
color:#00112c;
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:6px;
box-shadow:0 2px 7px rgba(0,15,45,.3);
max-height:375px;
z-index:2
}
.adyen-checkout__dropdown__list.adyen-checkout__dropdown__list--active{
margin-top:2px
}
.adyen-checkout__dropdown__element{
-moz-user-select:none;
-ms-hyphens:auto;
-ms-user-select:none;
-webkit-hyphens:auto;
-webkit-user-select:none;
border:1px solid transparent;
cursor:pointer;
font-size:.81em;
hyphens:auto;
line-height:20px;
outline:0;
padding:8px;
transition:background .2s ease-out,border-color .2s ease-out;
user-select:none;
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:rgba(230,233,235,.6)
}
.adyen-checkout__dropdown__element.adyen-checkout__dropdown__element--active{
background:rgba(0,102,255,.1)
}
.adyen-checkout__dropdown__element.adyen-checkout__dropdown__element--active:active,.adyen-checkout__dropdown__element.adyen-checkout__dropdown__element--active:focus,.adyen-checkout__dropdown__element.adyen-checkout__dropdown__element--active:hover{
background:rgba(0,102,255,.15)
}
.adyen-checkout__dropdown__element__icon{
border-radius:3px;
margin-right:8px;
max-height:26px;
max-width:40px
}
.adyen-checkout__dropdown+.adyen-checkout-input__inline-validation{
right:32px
}
.adyen-checkout__select-list{
background:#fff;
border:1px solid #b9c4c9;
border-radius:6px;
margin:0;
max-height:140px;
min-height:100px;
min-width:300px;
overflow-y:scroll;
padding:0;
width:100%
}
.adyen-checkout__select-list__item{
background:#fff;
border:1px solid transparent;
border-bottom-color:#e6e9eb;
cursor:pointer;
display:inline-block;
font-size:1em;
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(230,233,235,.6)
}
.adyen-checkout__select-list__item--selected{
background:rgba(0,102,255,.1);
font-weight:500
}
.adyen-checkout__select-list__item--selected:active,.adyen-checkout__select-list__item--selected:focus,.adyen-checkout__select-list__item--selected:hover{
background:rgba(0,102,255,.15)
}
.adyen-checkout__field-wrapper{
display:flex
}
.adyen-checkout__field--50{
width:50%
}
.adyen-checkout__field--50:first-child{
margin-right:8px
}
.adyen-checkout__field--50:nth-child(2){
margin-left:8px
}
.adyen-checkout__input{
background:#fff;
border:1px solid #b9c4c9;
border-radius:6px;
color:#00112c;
display:block;
font-family:inherit;
font-size:1em;
height:40px;
outline:none;
padding:5px 8px;
position:relative;
transition:border .2s ease-out,box-shadow .2s ease-out;
width:100%
}
.adyen-checkout__input:hover{
border-color:#99a3ad
}
.adyen-checkout__input:required{
box-shadow:none
}
.adyen-checkout__input--disabled,.adyen-checkout__input[readonly]{
background:#e6e9eb;
border-color:#e6e9eb
}
.adyen-checkout__input--disabled:hover{
border-color:#e6e9eb
}
.adyen-checkout__input-wrapper{
display: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:#0abf53
}
.adyen-checkout-input__inline-validation--invalid{
color:#d10244
}
.adyen-checkout__input--invalid{
border-color:#d10244
}
.adyen-checkout__input--valid{
border-bottom-color:#0abf53
}
.adyen-checkout__input--error,.adyen-checkout__input--error:hover,.adyen-checkout__input--invalid,.adyen-checkout__input--invalid:hover{
border-color:#d10244;
color:#d10244
}
.adyen-checkout__input::-webkit-input-placeholder{
color:#b9c4c9;
font-weight:200
}
.adyen-checkout__input:-ms-input-placeholder{
color:#b9c4c9;
font-weight:200
}
.adyen-checkout__input::-ms-input-placeholder{
color:#b9c4c9;
font-weight:200
}
.adyen-checkout__input::placeholder{
color:#b9c4c9;
font-weight:200
}
.adyen-checkout__input--focus,.adyen-checkout__input--focus:hover,.adyen-checkout__input:active,.adyen-checkout__input:active:hover,.adyen-checkout__input:focus,.adyen-checkout__input:focus:hover{
border:1px solid #06f;
box-shadow:0 0 0 2px #99c2ff
}
.adyen-checkout__input[readonly],.adyen-checkout__input[readonly]:hover{
background-color:#e6e9eb;
border-color:transparent;
color:#687282;
cursor:default
}
.adyen-checkout__fieldset{
display:block;
padding-bottom:8px;
width:100%
}
.adyen-checkout__fieldset:last-of-type{
padding-bottom:0
}
.adyen-checkout__fieldset+.adyen-checkout__fieldset{
margin-top:16px
}
.adyen-checkout__fieldset__title{
color:#687282;
display:block;
font-size:.68em;
font-weight:700;
letter-spacing:1px;
margin:0;
padding:0 0 8px;
text-transform:uppercase
}
.adyen-checkout__field-group,.adyen-checkout__fieldset__fields{
display:flex;
flex-wrap:wrap;
justify-content:space-between;
width:100%
}
.adyen-checkout__field-group:last-of-type .adyen-checkout__field{
margin-bottom:0
}
.adyen-checkout__field--col-70{
width:calc(70% - 8px)
}
.adyen-checkout__field--col-30{
width:calc(30% - 8px)
}
.adyen-checkout__field--col-50{
width:calc(50% - 8px)
}
.adyen-checkout__fieldset--readonly{
color:#00112c;
font-size:.81em;
line-height:19px;
margin:0
}
.adyen-checkout__open-invoice .adyen-checkout__checkbox--consent-checkbox{
max-width:540px
}
.adyen-checkout__open-invoice .adyen-checkout__checkbox{
margin:0 0 8px
}
.adyen-checkout__open-invoice .adyen-checkout__checkbox:only-of-type{
margin-bottom:0
}
.adyen-checkout__open-invoice .adyen-checkout__checkbox--consent-checkbox{
margin:0
}
.adyen-checkout__open-invoice .adyen-checkout__field--gender .adyen-checkout__radio_group{
display:flex
}
.adyen-checkout__open-invoice .adyen-checkout__field--gender .adyen-checkout__radio_group>label{
margin-right:16px
}
.adyen-checkout__open-invoice .adyen-checkout__field--gender .adyen-checkout__label--focused .adyen-checkout__label__text,.adyen-checkout__open-invoice .adyen-checkout__field--gender .adyen-checkout__label__text{
color:#00112c
}
.adyen-checkout__open-invoice .adyen-checkout__fieldset--billingAddress{
padding-bottom:8px
}
.adyen-checkout__open-invoice .adyen-checkout__fieldset--deliveryAddress{
margin-top:24px;
padding-bottom:8px
}
.adyen-checkout__open-invoice .adyen-checkout__input--separateDeliveryAddress{
margin-bottom:0
}
.adyen-checkout__open-invoice .adyen-checkout__field--dateOfBirth{
width:calc(50% - 8px)
}
.adyen-checkout__open-invoice .adyen-checkout__field--country,.adyen-checkout__open-invoice .adyen-checkout__field--street{
width:calc(70% - 8px)
}
.adyen-checkout__open-invoice .adyen-checkout__field--houseNumberOrName,.adyen-checkout__open-invoice .adyen-checkout__field--postalCode{
width:calc(30% - 8px)
}
.adyen-checkout__button{
background:#00112c;
border:0;
border-radius:6px;
color:#fff;
cursor:pointer;
font-size:1em;
font-weight:500;
height:48px;
margin:0;
padding:15px;
text-decoration:none;
transition:background .3s ease-out,box-shadow .3s ease-out;
width:100%
}
.adyen-checkout__button--pay{
margin-top:24px
}
.adyen-checkout__button--standalone{
margin-top:0
}
.adyen-checkout__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__button:focus{
box-shadow:0 0 0 2px #99c2ff;
outline:0
}
.adyen-checkout__button:hover{
background:#1c3045;
box-shadow:0 0,0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14)
}
.adyen-checkout__button:active{
background:#3a4a5c
}
.adyen-checkout__button:hover:focus{
box-shadow:0 0 0 2px #99c2ff,0 3px 4px rgba(0,15,45,.2)
}
.adyen-checkout__button--loading{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
background:#687282;
box-shadow:none;
pointer-events:none;
user-select:none
}
.adyen-checkout__button .adyen-checkout__spinner{
border-color:transparent #fff #fff
}
.adyen-checkout__button__content{
align-items:center;
display:flex;
justify-content:center
}
.adyen-checkout__button__icon{
margin-right:12px
}
.adyen-checkout__button__text{
display:block;
justify-content:center;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap
}
.adyen-checkout__button.adyen-checkout__button--inline{
display:block;
font-size:.81em;
height:auto;
padding:10px 8px;
width:auto
}
.adyen-checkout__button.adyen-checkout__button--secondary{
background:rgba(0,102,255,.1);
border:1px solid transparent;
color:#06f;
padding:10px 12px
}
.adyen-checkout__button.adyen-checkout__button--secondary:hover{
background:rgba(0,102,255,.2);
box-shadow:none
}
.adyen-checkout__button.adyen-checkout__button--secondary:active,.adyen-checkout__button.adyen-checkout__button--secondary:active:hover{
background:rgba(0,102,255,.3);
box-shadow:none
}
.adyen-checkout__button.adyen-checkout__button--completed,.adyen-checkout__button.adyen-checkout__button--completed:active,.adyen-checkout__button.adyen-checkout__button--completed:active:hover,.adyen-checkout__button.adyen-checkout__button--completed:hover{
background:#0abf53;
color:#fff
}
.adyen-checkout__button.adyen-checkout__button--completed .adyen-checkout__button__icon{
-webkit-filter:brightness(0) invert(1);
filter:brightness(0) invert(1)
}
.adyen-checkout__applepay__button{
height:40px;
width:240px
}
.adyen-checkout__dropin .adyen-checkout__applepay__button{
width:100%
}
.adyen-checkout__card-input__form{
transition:opacity .25s ease-out
}
.adyen-checkout__card__cardNumber{
max-width:400px
}
.adyen-checkout__card__cardNumber__input{
padding:5px 8px
}
.adyen-checkout__card__exp-date__input--oneclick{
font-weight:400;
line-height:30px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap
}
.adyen-checkout__card__holderName,.adyen-checkout__field--expiryDate,.adyen-checkout__field--storedCard{
margin-bottom:0
}
.adyen-checkout__card__holderName,.adyen-checkout__store-details{
margin-top:16px
}
.adyen-checkout__field--cardNumber .adyen-checkout__input--error .adyen-checkout__card__cardNumber__brandIcon{
display:none
}
.adyen-checkout__field--cardNumber .adyen-checkout__input--valid:not(.adyen-checkout__card__cardNumber__input--noBrand)+.adyen-checkout-input__inline-validation--valid{
display:none
}
.adyen-checkout__giropay__no-results{
color:#687282;
display:block;
font-size:.81em;
padding:0 0 0 2px
}
.adyen-checkout__giropay__placeholder{
color:#b9c4c9;
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:.81em;
line-height:16px;
vertical-align:middle
}
.adyen-checkout__giropay__error{
color:#d10244;
font-size:.81em
}
.adyen-checkout__dropin .gpay-button.long{
height:48px;
padding:15px 24px 13px;
transition:background-color .3s ease-out,box-shadow .3s ease-out;
width:100%
}
.adyen-checkout__field--issuer-list{
margin-bottom:0
}
.adyen-checkout__econtext-input__field{
display:flex;
flex-wrap:wrap
}
.adyen-checkout__econtext-input__field .adyen-checkout__field--firstName,.adyen-checkout__econtext-input__field .adyen-checkout__field--lastName{
max-width:100%;
min-width:250px;
width:calc(50% - 8px)
}
.adyen-checkout__econtext-input__field .adyen-checkout__field--firstName{
margin-right:16px
}
.adyen-checkout__voucher-result{
border-radius:12px;
box-sizing:border-box;
position:relative;
text-align:center
}
.adyen-checkout__voucher-result__bottom,.adyen-checkout__voucher-result__top{
background:#fff;
border:1px solid #d4d9db
}
.adyen-checkout__voucher-result__top{
border-bottom:0;
border-radius:12px 12px 0 0;
padding:40px 0 24px
}
.adyen-checkout__voucher-result__bottom{
border-radius:0 0 12px 12px;
border-top:0
}
.adyen-checkout__voucher-result__separator{
align-items:center;
background:#fff;
display:flex;
height:13px;
margin:0 auto;
position:relative;
width:calc(100% - 14px)
}
.adyen-checkout__voucher-result__separator:after,.adyen-checkout__voucher-result__separator:before{
background-image:url(data:image/svg+xml;
base64,PHN2ZyB3aWR0aD0iNyIgaGVpZ2h0PSIxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBjbGlwLXBhdGg9InVybCgjY2xpcDApIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTAgMGw1IDIgMS41IDRIN1YwSDB6bTAgMTNsNS0yIDEuNS00SDd2NkgweiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik02LjQyMyA2LjVDNi40MjMgMy4zMTIgMy43ODMuNzU2LjUuNTE4YzMuMzg2LjIzNiA2IDIuODU1IDYgNS45ODIgMCAzLjEyNy0yLjYxNCA1Ljc0Ni02IDUuOTgzdi0uMDAxYzMuMjg0LS4yMzcgNS45MjMtMi43OTQgNS45MjMtNS45ODJ6IiBzdHJva2U9IiNENEQ5REIiLz48cGF0aCBmaWxsPSIjRDREOURCIiBkPSJNMCAwaDF2MUgwek0wIDEyaDF2MUgweiIvPjwvZz48ZGVmcz48Y2xpcFBhdGggaWQ9ImNsaXAwIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwaDd2MTNIMHoiLz48L2NsaXBQYXRoPjwvZGVmcz48L3N2Zz4=)
}
.adyen-checkout__voucher-result__separator:before{
background-position:100%;
background-repeat:no-repeat;
content:"";
height:13px;
left:-7px;
position:absolute;
top:0;
width:7px
}
.adyen-checkout__voucher-result__separator:after{
-webkit-transform:rotate(-180deg);
background-position:100%;
background-repeat:no-repeat;
content:"";
height:13px;
position:absolute;
right:-7px;
top:0;
transform:rotate(-180deg);
width:7px
}
.adyen-checkout__voucher-result__separator__inner{
border-top:1px solid #e6e9eb;
width:100%
}
.adyen-checkout__voucher-result__image{
align-items:center;
display:flex;
justify-content:center;
margin-bottom:40px;
width:100%
}
.adyen-checkout__voucher-result__image__wrapper{
display:block;
height:48px;
margin:0 24px;
position:relative
}
.adyen-checkout__voucher-result__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__voucher-result__image__wrapper:nth-child(2):before{
border-left:1px solid #d4d9db;
content:"";
height:64px;
left:-24.5px;
position:absolute;
top:-8px;
width:1px
}
.adyen-checkout__voucher-result__image__brand,.adyen-checkout__voucher-result__image__issuer{
border-radius:3px;
height:48px
}
.adyen-checkout__voucher-result__introduction{
color:#00112c;
font-size:.81em;
line-height:19px;
margin:0 auto;
max-width:400px;
text-align:center
}
.adyen-checkout__voucher-result__amount{
color:#00112c;
font-size:1em;
font-weight:700;
margin:24px auto 0;
text-align:center
}
.adyen-checkout__voucher-result__surcharge{
color:#687282;
display:block;
font-size:.81em;
font-weight:400;
line-height:19px;
text-align:center
}
.adyen-checkout__voucher-result__code__label{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
display:block;
font-weight:400;
left:0;
line-height:19px;
margin:0 auto;
position:absolute;
right:0;
top:-2px;
user-select:none;
width:auto
}
.adyen-checkout__voucher-result__code__label:before{
content:"";
position:absolute
}
.adyen-checkout__voucher-result__code__label__text{
background:#fff;
color:#00112c;
font-size:13px;
letter-spacing:normal;
line-height:1;
padding:0 8px
}
.adyen-checkout__voucher-result__code__barcode{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
display:block;
height:56px;
margin:0 auto 8px;
max-width:100%;
user-select:none
}
.adyen-checkout__voucher-result__code{
-moz-user-select:all;
-ms-user-select:all;
-webkit-user-select:all;
border-width:1px 0;
color:#00112c;
display:inline-block;
font-size:1.5em;
font-weight:700;
letter-spacing:1px;
line-height:1.2;
margin:0 auto;
padding:16px 48px;
position:relative;
text-align:center;
user-select:all;
width:100%;
word-break:break-word
}
.adyen-checkout__voucher-result__details{
list-style:none;
margin:-1px auto 0;
padding:0
}
.adyen-checkout__voucher-result__details__item{
border-top:1px solid #e6e9eb;
color:#00112c;
display:flex;
font-size:.81em;
justify-content:space-between;
padding:16px 24px;
word-break:break-word
}
.adyen-checkout__voucher-result__details__item:last-child{
margin-bottom:0
}
.adyen-checkout__voucher-result__details__label{
max-width:50%;
text-align:left
}
.adyen-checkout__voucher-result__details__value{
font-weight:700;
max-width:50%;
text-align:right
}
.adyen-checkout__voucher-result__actions{
align-items:center;
display:flex;
justify-content:center;
list-style:none;
margin:0 auto 32px;
max-width:100%;
min-width:200px;
padding:0;
width:300px
}
.adyen-checkout__voucher-result__actions__item{
margin:0 4px
}
.adyen-checkout__link--more-information{
display:block;
font-size:.81em;
font-weight:400;
margin:16px 0;
text-align:center
}
.adyen-checkout__phone-input__container{
display:flex
}
.adyen-checkout__phone-input__prefix{
margin-bottom:0;
margin-right:.5em;
width:30%
}
.adyen-checkout__input--phone-number{
margin-bottom:0;
width:70%
}
.adyen-checkout__iban-input__number{
padding:5px 36px 5px 8px;
text-transform:uppercase
}
.adyen-checkout__threeds2__challenge,.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__threeds2__challenge.adyen-checkout__threeds2__challenge--05{
overflow:hidden;
padding-top:56.25%;
position:relative
}
.adyen-checkout__threeds2__challenge.adyen-checkout__threeds2__challenge--05 .adyen-checkout__iframe--threeDSIframe{
border:0;
height:100%;
left:0;
position:absolute;
top:0;
width:100%
}
.adyen-checkout__qr-loader{
background:#fff;
border:1px solid #d4d9db;
border-radius:6px;
padding:40px;
text-align:center
}
.adyen-checkout__qr-loader--app{
border:0;
border-radius:0;
padding:0
}
.adyen-checkout__qr-loader__brand-logo{
max-height:50px;
width:110px
}
.adyen-checkout__qr-loader__subtitle{
margin-top:32px
}
.adyen-checkout__qr-loader__subtitle--result{
margin-bottom:32px
}
.adyen-checkout__qr-loader__payment_amount,.adyen-checkout__qr-loader__subtitle{
color:#00112c;
font-size:1em;
line-height:19px
}
.adyen-checkout__qr-loader__icon{
height:88px;
width:88px
}
.adyen-checkout__qr-loader__icon--result{
margin-bottom:100px
}
.adyen-checkout__qr-loader__payment_amount{
font-weight:700
}
.adyen-checkout__qr-loader__progress{
background:#d4d9db;
border-radius:24px;
height:4px;
margin:32px auto 12px;
padding-right:3%;
width:152px
}
.adyen-checkout__qr-loader__percentage{
background:#06f;
border-radius:24px;
display:block;
height:100%
}
.adyen-checkout__qr-loader__countdown{
color:#687282;
font-size:.81em
}
.adyen-checkout__qr-loader>.adyen-checkout__spinner__wrapper{
margin:60px 0
}
.adyen-checkout__qr-loader__separator__label{
background:#fff;
border-radius:50%;
color:#687282;
display:inline-block;
height:34px;
line-height:34px;
position:relative;
width:34px;
z-index:1
}
.adyen-checkout__qr-loader__separator__line{
-webkit-transform:translateY(-17px);
border-top:1px solid #d4d9db;
display:block;
transform:translateY(-17px)
}
.adyen-checkout__button.adyen-checkout__button--qr-loader{
display:block;
text-decoration:none
}
.adyen-checkout__doku-input__field{
display:flex;
flex-wrap:wrap
}
.adyen-checkout__doku-input__field .adyen-checkout__field--firstName,.adyen-checkout__doku-input__field .adyen-checkout__field--lastName{
max-width:100%;
min-width:250px;
width:calc(50% - 8px)
}
.adyen-checkout__doku-input__field .adyen-checkout__field--firstName{
margin-right:16px
}
.adyen-checkout__voucher-result--boletobancario .adyen-checkout__voucher-result__code{
font-size:.81em;
line-height:19px;
padding:24px;
word-break:break-all
}
.adyen-checkout__voucher-result--oxxo .adyen-checkout__voucher-result__code{
font-size:.81em;
line-height:19px;
padding:24px;
word-break:break-all
}
.adyen-checkout__payment-method{
background:#fff;
border:1px solid #e6e9eb;
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:12px;
border-top-right-radius:12px;
margin-top:0
}
.adyen-checkout__payment-method--next-selected,.adyen-checkout__payment-method:last-child{
border-bottom-left-radius:12px;
border-bottom-right-radius:12px;
margin-bottom:0
}
.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:.3
}
.adyen-checkout__payment-method__header{
align-items:center;
color:#00112c;
display:flex;
flex-wrap:nowrap;
font-size:1em;
font-weight:400;
justify-content:space-between;
padding:16px 16px 16px 48px;
position:relative;
transition:background .1s ease-out;
width:100%
}
.adyen-checkout__payment-method--standalone .adyen-checkout__payment-method__header{
padding:16px
}
.adyen-checkout__payment-method__header__title{
align-items:center;
display:flex;
flex-shrink:0;
margin-right:16px;
max-width:100%
}
.adyen-checkout__payment-method__surcharge{
color:#687282;
margin-left:5px
}
.adyen-checkout__payment-method--selected{
background:#f7f8f9;
border:1px solid #e6e9eb;
border-radius:12px;
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{
flex-wrap:wrap
}
.adyen-checkout__payment-method__name{
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap
}
.adyen-checkout__payment-method__name--selected{
font-weight:500
}
.adyen-checkout__payment-method__details{
padding:0 16px
}
.adyen-checkout__payment-method__details__content{
margin:0 0 16px
}
.adyen-checkout__payment-method__image__wrapper{
height:26px;
opacity:0;
position:relative;
transition:opacity .15s ease-out;
width:40px
}
.adyen-checkout__payment-method__image__wrapper--loaded{
opacity:1
}
.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__brands{
display:flex;
flex-basis:auto;
flex-shrink:1;
flex-wrap:wrap;
height:16px;
margin:4px 0;
overflow:hidden;
text-align:right
}
.adyen-checkout__payment-method--selected .adyen-checkout__payment-method__brands{
height:auto;
overflow:visible;
text-align:left
}
.adyen-checkout__payment-method__brands .adyen-checkout__payment-method__image__wrapper{
display:inline-block;
height:16px;
margin-right:4px;
transition:opacity .2s ease-out;
width:24px
}
.adyen-checkout__payment-method__brands .adyen-checkout__payment-method__image__wrapper:last-child{
margin:0
}
.adyen-checkout__payment-method--selected .adyen-checkout__payment-method__brands .adyen-checkout__payment-method__image__wrapper{
margin-bottom:4px
}
.adyen-checkout__payment-method__brands img{
height:16px;
width:24px
}
.adyen-checkout__payment-method__image__wrapper--disabled{
opacity:.25
}
.adyen-checkout__payment-method__disable-confirmation{
align-items:center;
background:#e6e9eb;
color:#00112c;
display:flex;
font-size:1em;
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:6px;
cursor:pointer;
font-size:.81em;
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:#00112c;
color:#00112c
}
.adyen-checkout__payment-method__radio{
background-color:#fff;
border:1px solid #b9c4c9;
border-radius:50%;
height:16px;
left:16px;
position:absolute;
transition:border-color .2s ease-out,box-shadow .2s ease-out;
width:16px
}
.adyen-checkout__payment-method--standalone .adyen-checkout__payment-method__radio{
display:none
}
.adyen-checkout__payment-method__radio:after{
-webkit-transform:translateY(-50%) scale(0);
background-color:#fff;
border-radius:50%;
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:#99a3ad;
box-shadow:0 0 0 2px #d4d9db;
cursor:pointer
}
.adyen-checkout__payment-method__radio--selected{
background-color:#06f;
border:0;
transition:all .3s ease-out
}
.adyen-checkout__payment-method__radio--selected:hover{
box-shadow:0 0 0 2px rgba(0,102,255,.4)
}
.adyen-checkout__payment-method__radio--selected:after{
-webkit-transform:translateY(-50%) scale(1);
transform:translateY(-50%) scale(1)
}
.adyen-checkout__status{
align-items:center;
background-color:#fff;
border:1px solid #d4d9db;
border-radius:6px;
color:#00112c;
display:flex;
flex-direction:column;
font-size:1em;
height:350px;
justify-content:center;
margin:0;
padding:32px;
text-align:center
}
.adyen-checkout__status__icon{
margin-bottom:24px
}
.adyen-checkout__dropin,.adyen-checkout__dropin *,.adyen-checkout__dropin :after,.adyen-checkout__dropin :before{
box-sizing:border-box
}
.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:#06f;
text-decoration:none
}
.adyen-checkout__link:hover{
text-decoration:underline
}
/* Checkout component Adyen styling end */ /* Checkout component Adyen styling end */
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
define(
[
],
function () {
'use strict';
return {
getOriginKey: function () {
return window.checkoutConfig.payment.adyenCc.originKey;
},
showLogo: function () {
return window.checkoutConfig.payment.adyen.showLogo;
},
getLocale: function () {
return window.checkoutConfig.payment.adyenCc.locale;
},
getCheckoutEnvironment: function () {
return window.checkoutConfig.payment.adyenCc.checkoutEnvironment;
},
};
}
);
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
define(
[
'ko'
],
function (ko) {
'use strict';
return ko.observableArray([]);
}
);
...@@ -4,37 +4,23 @@ ...@@ -4,37 +4,23 @@
*/ */
define( define(
[ [
'ko',
'underscore', 'underscore',
'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/quote',
'Adyen_Payment/js/model/adyen-method-list',
'Magento_Customer/js/model/customer', 'Magento_Customer/js/model/customer',
'Magento_Checkout/js/model/url-builder', 'Magento_Checkout/js/model/url-builder',
'mage/storage' 'mage/storage',
'Adyen_Payment/js/bundle',
], ],
function (_, quote, methodList, customer, urlBuilder, storage) { function (ko, _, quote, customer, urlBuilder, storage, adyenComponent) {
'use strict'; 'use strict';
var checkoutComponent = {};
var paymentMethods = ko.observable({})
return { return {
/**
* Populate the list of payment methods
* @param {Array} methods
*/
setPaymentMethods: function (methods) {
methodList(methods);
},
/**
* Get the list of available payment methods.
* @returns {Array}
*/
getAvailablePaymentMethods: function () {
return methodList();
},
/** /**
* Retrieve the list of available payment methods from the server * Retrieve the list of available payment methods from the server
*/ */
retrieveAvailablePaymentMethods: function (callback) { retrieveAvailablePaymentMethods: function () {
var self = this;
// retrieve payment methods // retrieve payment methods
var serviceUrl, var serviceUrl,
payload; payload;
...@@ -51,28 +37,60 @@ define( ...@@ -51,28 +37,60 @@ define(
shippingAddress: quote.shippingAddress() shippingAddress: quote.shippingAddress()
}; };
storage.post( return storage.post(
serviceUrl, serviceUrl,
JSON.stringify(payload) JSON.stringify(payload),
).done( true
function (response) {
self.setPaymentMethods(response);
if (callback) {
callback();
}
}
).fail(
function () {
self.setPaymentMethods([]);
}
) )
}, },
/**
* 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
);
},
getOrderPaymentStatus: function (orderId) { getOrderPaymentStatus: function (orderId) {
var serviceUrl = urlBuilder.createUrl('/adyen/orders/:orderId/payment-status', { var serviceUrl = urlBuilder.createUrl('/adyen/orders/:orderId/payment-status', {
orderId: orderId orderId: orderId
}); });
return storage.get(serviceUrl); return storage.get(serviceUrl);
},
initCheckoutComponent: function(paymentMethodsResponse, originKey, locale, environment, ) {
checkoutComponent = new AdyenCheckout({
locale: locale,
originKey: originKey,
environment: environment,
paymentMethodsResponse: paymentMethodsResponse,
consentCheckbox: false,
visibility: {
personalDetails: 'editable',
billingAddress: 'editable',
separateDeliveryAddress: 'hidden',
deliveryAddress: 'hidden'
}
});
paymentMethods(paymentMethodsResponse.paymentMethods);
},
getCheckoutComponent: function() {
return checkoutComponent;
},
getPaymentMethodsObservable: function() {
return paymentMethods;
} }
}; };
} }
......
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
define(
[
'ko',
'jquery',
],
function (ko, $) {
'use strict';
return {
/**
*
* @param installments
* @param grandTotal
* @param precision
* @param currencyCode
* @returns {Array}
*/
getInstallmentsWithPrices: function (installments, grandTotal, precision, currencyCode) {
let numberOfInstallments = [];
let dividedAmount = 0;
let dividedString = "";
$.each(installments, function (amount, installment) {
if (grandTotal >= amount) {
dividedAmount = (grandTotal / installment).toFixed(precision);
dividedString = installment + " x " + dividedAmount + " " + currencyCode;
numberOfInstallments.push({
key: [dividedString],
value: installment
});
}
});
return numberOfInstallments;
}
};
}
);
/**
* 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 {
/**
* 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
);
}
};
}
);
...@@ -24,11 +24,19 @@ ...@@ -24,11 +24,19 @@
define( define(
[ [
'uiComponent', 'uiComponent',
'Magento_Checkout/js/model/payment/renderer-list' 'Magento_Checkout/js/model/payment/renderer-list',
'Adyen_Payment/js/model/adyen-payment-service',
'Adyen_Payment/js/model/adyen-configuration',
'Magento_Checkout/js/model/quote',
'Magento_Customer/js/model/customer'
], ],
function ( function (
Component, Component,
rendererList rendererList,
adyenPaymentService,
adyenConfiguration,
quote,
customer
) { ) {
'use strict'; 'use strict';
rendererList.push( rendererList.push(
...@@ -63,16 +71,13 @@ define( ...@@ -63,16 +71,13 @@ define(
); );
/** Add view logic here if needed */ /** Add view logic here if needed */
return Component.extend({ return Component.extend({
defaults: {
countryCode: ""
},
initialize: function () { initialize: function () {
var self = this; var self = this;
this._super();
// include checkout card component javascript this._super();
var checkoutCardComponentScriptTag = document.createElement('script');
checkoutCardComponentScriptTag.id = "AdyenCheckoutCardComponentScript";
checkoutCardComponentScriptTag.src = self.getCheckoutCardComponentSource();
checkoutCardComponentScriptTag.type = "text/javascript";
document.head.appendChild(checkoutCardComponentScriptTag);
if (this.isGooglePayEnabled()) { if (this.isGooglePayEnabled()) {
var googlepayscript = document.createElement('script'); var googlepayscript = document.createElement('script');
...@@ -80,13 +85,59 @@ define( ...@@ -80,13 +85,59 @@ define(
googlepayscript.type = "text/javascript"; googlepayscript.type = "text/javascript";
document.head.appendChild(googlepayscript); document.head.appendChild(googlepayscript);
} }
if (customer.isLoggedIn()) {
self.setAdyenPaymentMethods();
}
quote.shippingAddress.subscribe(function() {
if (!!quote.shippingAddress().countryId && self.countryCode !== quote.shippingAddress().countryId) {
self.countryCode = quote.shippingAddress().countryId;
self.setAdyenPaymentMethods();
}
})
}, },
getCheckoutCardComponentSource: function () { setAdyenPaymentMethods: function() {
return window.checkoutConfig.payment.checkoutCardComponentSource; adyenPaymentService.retrieveAvailablePaymentMethods().done(function (response) {
var responseJson = JSON.parse(response);
var paymentMethodsResponse = responseJson.paymentMethodsResponse;
// TODO check if this is still required or if can be outsourced for the generic component, or checkout can create a ratepay component
/*if (!!window.checkoutConfig.payment.adyenHpp) {
if (JSON.stringify(paymentMethods).indexOf("ratepay") > -1) {
var ratePayId = window.checkoutConfig.payment.adyenHpp.ratePayId;
var dfValueRatePay = self.getRatePayDeviceIdentToken();
window.di = {
t: dfValueRatePay.replace(':', ''),
v: ratePayId,
l: 'Checkout'
};
// Load Ratepay script
var ratepayScriptTag = document.createElement('script');
ratepayScriptTag.src = "//d.ratepay.com/" + ratePayId + "/di.js";
ratepayScriptTag.type = "text/javascript";
document.body.appendChild(ratepayScriptTag);
}
}*/
// Initialises adyen checkout main component with default configuration
adyenPaymentService.initCheckoutComponent(
paymentMethodsResponse,
adyenConfiguration.getOriginKey(),
adyenConfiguration.getLocale(),
adyenConfiguration.getCheckoutEnvironment()
);
})
}, },
isGooglePayEnabled: function () { isGooglePayEnabled: function () {
return window.checkoutConfig.payment.adyenGooglePay.active; return window.checkoutConfig.payment.adyenGooglePay.active;
},
getRatePayDeviceIdentToken: function () {
return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
} }
}); });
} }
); );
\ No newline at end of file
...@@ -28,7 +28,6 @@ define( ...@@ -28,7 +28,6 @@ define(
'Magento_Payment/js/model/credit-card-validation/credit-card-data', 'Magento_Payment/js/model/credit-card-validation/credit-card-data',
'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Checkout/js/model/payment/additional-validators',
'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/quote',
'Adyen_Payment/js/model/installments',
'mage/url', 'mage/url',
'Magento_Vault/js/view/payment/vault-enabler', 'Magento_Vault/js/view/payment/vault-enabler',
'Magento_Checkout/js/model/url-builder', 'Magento_Checkout/js/model/url-builder',
...@@ -36,10 +35,9 @@ define( ...@@ -36,10 +35,9 @@ define(
'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/full-screen-loader',
'Magento_Paypal/js/action/set-payment-method', 'Magento_Paypal/js/action/set-payment-method',
'Magento_Checkout/js/action/select-payment-method', 'Magento_Checkout/js/action/select-payment-method',
'Adyen_Payment/js/threeds2-js-utils',
'Adyen_Payment/js/model/threeds2',
'Magento_Checkout/js/model/error-processor', 'Magento_Checkout/js/model/error-processor',
'Adyen_Payment/js/model/adyen-payment-service' 'Adyen_Payment/js/model/adyen-payment-service',
'Adyen_Payment/js/model/adyen-configuration'
], ],
function ( function (
$, $,
...@@ -49,7 +47,6 @@ define( ...@@ -49,7 +47,6 @@ define(
creditCardData, creditCardData,
additionalValidators, additionalValidators,
quote, quote,
installmentsHelper,
url, url,
VaultEnabler, VaultEnabler,
urlBuilder, urlBuilder,
...@@ -57,10 +54,9 @@ define( ...@@ -57,10 +54,9 @@ define(
fullScreenLoader, fullScreenLoader,
setPaymentMethodAction, setPaymentMethodAction,
selectPaymentMethodAction, selectPaymentMethodAction,
threeDS2Utils,
threeds2,
errorProcessor, errorProcessor,
adyenPaymentService adyenPaymentService,
adyenConfiguration
) { ) {
'use strict'; 'use strict';
...@@ -72,10 +68,10 @@ define( ...@@ -72,10 +68,10 @@ define(
defaults: { defaults: {
template: 'Adyen_Payment/payment/cc-form', template: 'Adyen_Payment/payment/cc-form',
creditCardOwner: '',
storeCc: false,
installment: '', installment: '',
creditCardDetailsValid: false stateData: {},
checkoutComponent: {},
cardComponent: {}
}, },
/** /**
* @returns {exports.initialize} * @returns {exports.initialize}
...@@ -85,26 +81,14 @@ define( ...@@ -85,26 +81,14 @@ define(
this.vaultEnabler = new VaultEnabler(); this.vaultEnabler = new VaultEnabler();
this.vaultEnabler.setPaymentCode(this.getVaultCode()); this.vaultEnabler.setPaymentCode(this.getVaultCode());
this.vaultEnabler.isActivePaymentTokenEnabler(false); this.vaultEnabler.isActivePaymentTokenEnabler(false);
this.checkoutComponent = adyenPaymentService.getCheckoutComponent();
// initialize adyen component for general use
this.checkout = new AdyenCheckout({
locale: this.getLocale()
});
return this; return this;
}, },
initObservable: function () { initObservable: function () {
this._super() this._super()
.observe([ .observe([
'creditCardType',
'creditCardOwner',
'creditCardNumber',
'securityCode',
'expiryMonth',
'expiryYear',
'installment', 'installment',
'installments',
'creditCardDetailsValid',
'placeOrderAllowed' 'placeOrderAllowed'
]); ]);
...@@ -112,92 +96,57 @@ define( ...@@ -112,92 +96,57 @@ define(
}, },
/** /**
* Returns true if card details can be stored * Returns true if card details can be stored
* The user is logged in and
* Billing agreement or vault is ebabled
*
* @returns {*|boolean} * @returns {*|boolean}
*/ */
getEnableStoreDetails: function () { getEnableStoreDetails: function () {
return this.canCreateBillingAgreement() && !this.isVaultEnabled(); if (customer.isLoggedIn()) {
// TODO create new configuration to enable stored details without vault and billing agreement
// since we noew use the payment Methods response to fetch the stored payment methods
return this.canCreateBillingAgreement() || this.isVaultEnabled();
}
return false;
}, },
/** /**
* Renders the secure fields, * Renders checkout card component
* creates the card component,
* sets up the callbacks for card components and
* set up the installments
*/ */
renderSecureFields: function () { renderCardComponent: function () {
var self = this; if (!adyenConfiguration.getOriginKey()) {
if (!self.getOriginKey()) {
return; return;
} }
self.installments(0); var self = this;
// installments configuration
// installments var installmentsConfiguration = this.getAllInstallments();
var allInstallments = self.getAllInstallments(); // TODO get config from admin configuration
var cardNode = document.getElementById('cardContainer'); installmentsConfiguration = '[[0,2,3],[2,3,3]]'; // DUmmy data for testing
var placeOrderAllowed = self.placeOrderAllowed.bind(self);
function handleOnChange(state, component) {
if (!!state.isValid) {
self.stateData = state.data;
placeOrderAllowed(true);
} else {
placeOrderAllowed(false);
}
};
self.cardComponent = self.checkout.create('card', { // Extra configuration object for card payments
originKey: self.getOriginKey(), const configuration = {
environment: self.getCheckoutEnvironment(),
type: 'card',
hasHolderName: true, hasHolderName: true,
holderNameRequired: true, holderNameRequired: true,
enableStoreDetails: self.getEnableStoreDetails(), enableStoreDetails: self.getEnableStoreDetails(),
groupTypes: self.getAvailableCardTypeAltCodes(), groupTypes: self.getAvailableCardTypeAltCodes(),
installments: installmentsConfiguration,
onChange: handleOnChange
};
onChange: function (state, component) { // create and mount
if (!!state.isValid && !component.state.errors.encryptedSecurityCode) { this.cardComponent = this.checkoutComponent.create('card', configuration).mount('#cardContainer');
self.storeCc = !!state.data.storePaymentMethod;
self.creditCardNumber(state.data.paymentMethod.encryptedCardNumber);
self.expiryMonth(state.data.paymentMethod.encryptedExpiryMonth);
self.expiryYear(state.data.paymentMethod.encryptedExpiryYear);
self.securityCode(state.data.paymentMethod.encryptedSecurityCode);
self.creditCardOwner(state.data.paymentMethod.holderName);
self.creditCardDetailsValid(true);
self.placeOrderAllowed(true);
} else {
self.creditCardDetailsValid(false);
self.placeOrderAllowed(false);
}
},
onBrand: function (state) {
// Define the card type
// translate adyen card type to magento card type
var creditCardType = self.getCcCodeByAltCode(state.brand);
if (creditCardType) {
// If the credit card type is already set, check if it changed or not
if (!self.creditCardType() || self.creditCardType() && self.creditCardType() != creditCardType) {
var numberOfInstallments = [];
if (creditCardType in allInstallments) {
// get for the creditcard the installments
var installmentCreditcard = allInstallments[creditCardType];
var grandTotal = quote.totals().grand_total;
var precision = quote.getPriceFormat().precision;
var currencyCode = quote.totals().quote_currency_code;
numberOfInstallments = installmentsHelper.getInstallmentsWithPrices(installmentCreditcard, grandTotal, precision, currencyCode);
}
if (numberOfInstallments) {
self.installments(numberOfInstallments);
} else {
self.installments(0);
}
}
// for BCMC as this is not a core payment method inside magento use maestro as brand detection
if (creditCardType == "BCMC") {
self.creditCardType("MI");
} else {
self.creditCardType(creditCardType);
}
} else {
self.creditCardType("")
self.installments(0);
}
}
}).mount(cardNode);
}, },
/** /**
* Rendering the 3DS2.0 components * Rendering the 3DS2.0 components
...@@ -210,33 +159,28 @@ define( ...@@ -210,33 +159,28 @@ define(
* @param type * @param type
* @param token * @param token
*/ */
renderThreeDS2Component: function (type, token, orderId) { renderThreeDS2Component: function (action, orderId) {
var self = this; var self = this;
var threeDS2Node = document.getElementById('threeDS2Container');
if (type == "IdentifyShopper") { // Handle identify shopper action
self.threeDS2IdentifyComponent = self.checkout if (action.type == 'threeDS2Fingerprint') {
.create('threeDS2DeviceFingerprint', { var configuration = {
fingerprintToken: token, onAdditionalDetails: function (result) {
onComplete: function (result) { var request = result.data;
self.threeDS2IdentifyComponent.unmount(); request.orderId = orderId;
var request = result.data; adyenPaymentService.processThreeDS2(request).done(function (responseJSON) {
request.orderId = orderId; self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
threeds2.processThreeDS2(request).done(function (responseJSON) { }).fail(function (result) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId) errorProcessor.process(result, self.messageContainer);
}).fail(function (result) { self.isPlaceOrderActionAllowed(true);
errorProcessor.process(result, self.messageContainer); fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true); });
fullScreenLoader.stopLoader();
});
},
onError: function (error) {
console.log(JSON.stringify(error));
} }
}); };
}
self.threeDS2IdentifyComponent.mount(threeDS2Node); // Handle challenge shopper action
} else if (type == "ChallengeShopper") { if (action.type == "threeDS2Challenge") {
fullScreenLoader.stopLoader(); fullScreenLoader.stopLoader();
var popupModal = $('#threeDS2Modal').modal({ var popupModal = $('#threeDS2Modal').modal({
...@@ -251,30 +195,25 @@ define( ...@@ -251,30 +195,25 @@ define(
popupModal.modal("openModal"); popupModal.modal("openModal");
self.threeDS2ChallengeComponent = self.checkout var configuration = {
.create('threeDS2Challenge', { size: '05',
challengeToken: token, onAdditionalDetails: function (result) {
size: '05', self.closeModal(popupModal);
onComplete: function (result) { fullScreenLoader.startLoader();
self.threeDS2ChallengeComponent.unmount(); var request = result.data;
self.closeModal(popupModal); request.orderId = orderId;
fullScreenLoader.startLoader(); adyenPaymentService.processThreeDS2(request).done(function (responseJSON) {
var request = result.data; self.validateThreeDS2OrPlaceOrder(responseJSON, orderId);
request.orderId = orderId; }).fail(function (result) {
threeds2.processThreeDS2(request).done(function (responseJSON) { errorProcessor.process(result, self.messageContainer);
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId); self.isPlaceOrderActionAllowed(true);
}).fail(function (result) { fullScreenLoader.stopLoader();
errorProcessor.process(result, self.messageContainer); });
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
onError: function (error) {
console.log(JSON.stringify(error));
} }
}); };
self.threeDS2ChallengeComponent.mount(threeDS2Node);
} }
self.checkoutComponent.createFromAction(action, configuration).mount('#threeDS2Container');
}, },
/** /**
* This method is a workaround to close the modal in the right way and reconstruct the threeDS2Modal. * This method is a workaround to close the modal in the right way and reconstruct the threeDS2Modal.
...@@ -296,27 +235,12 @@ define( ...@@ -296,27 +235,12 @@ define(
* @returns {{method: *}} * @returns {{method: *}}
*/ */
getData: function () { getData: function () {
const browserInfo = threeDS2Utils.getBrowserInfo();
var data = { var data = {
'method': this.item.method, 'method': this.item.method,
additional_data: { additional_data: {
'guestEmail': quote.guestEmail, 'state_data': JSON.stringify(this.stateData),
'cc_type': this.creditCardType(), 'combo_card_type': this.comboCardOption(),
'number': this.creditCardNumber(), 'channel': 'Web' //TODO pass channel from frontend
'cvc': this.securityCode(),
'expiryMonth': this.expiryMonth(),
'expiryYear': this.expiryYear(),
'holderName': this.creditCardOwner(),
'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,
'combo_card_type': this.comboCardOption()
} }
}; };
this.vaultEnabler.visitAdditionalData(data); this.vaultEnabler.visitAdditionalData(data);
...@@ -375,9 +299,12 @@ define( ...@@ -375,9 +299,12 @@ define(
var self = this; var self = this;
var response = JSON.parse(responseJSON); var response = JSON.parse(responseJSON);
if (!!response.threeDS2) { if (!!response.type && (
response.type == "threeDS2Fingerprint" ||
response.type == "threeDS2Challenge"
)) {
// render component // render component
self.renderThreeDS2Component(response.type, response.token, orderId); self.renderThreeDS2Component(response, orderId);
} else { } else {
window.location.replace(url.build( window.location.replace(url.build(
window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl
...@@ -402,28 +329,6 @@ define( ...@@ -402,28 +329,6 @@ define(
return true; return true;
}, },
/**
* Validates if the typed in card holder is valid
* - length validation, can not be empty
*
* @returns {boolean}
*/
isCardOwnerValid: function () {
if (this.creditCardOwner().length == 0) {
return false;
}
return true;
},
/**
* The card component send the card details validity in a callback which is saved in the
* creditCardDetailsValid observable
*
* @returns {*}
*/
isCreditCardDetailsValid: function () {
return this.creditCardDetailsValid();
},
/** /**
* Translates the card type alt code (used in Adyen) to card type code (used in Magento) if it's available * Translates the card type alt code (used in Adyen) to card type code (used in Magento) if it's available
* *
...@@ -457,13 +362,7 @@ define( ...@@ -457,13 +362,7 @@ define(
return window.checkoutConfig.payment.adyenCc.methodCode; return window.checkoutConfig.payment.adyenCc.methodCode;
}, },
getOriginKey: function () { getOriginKey: function () {
return window.checkoutConfig.payment.adyenCc.originKey; return adyenConfiguration.getOriginKey;
},
getCheckoutEnvironment: function () {
return window.checkoutConfig.payment.adyenCc.checkoutEnvironment;
},
getLocale: function () {
return window.checkoutConfig.payment.adyenCc.locale;
}, },
isActive: function () { isActive: function () {
return true; return true;
...@@ -481,23 +380,44 @@ define( ...@@ -481,23 +380,44 @@ define(
return false; return false;
}, },
//TODO create configuration for this on admin
isShowLegend: function () { isShowLegend: function () {
return true; return true;
}, },
//TODO create a configuration for information on admin
getLegend: function () {
return '';
},
showLogo: function () { showLogo: function () {
return window.checkoutConfig.payment.adyen.showLogo; return adyenConfiguration.showLogo;
}, },
/**
*
* @param type
* @returns {*}
*/
getIcons: function (type) { getIcons: function (type) {
return window.checkoutConfig.payment.adyenCc.icons.hasOwnProperty(type) return window.checkoutConfig.payment.adyenCc.icons.hasOwnProperty(type)
? window.checkoutConfig.payment.adyenCc.icons[type] ? window.checkoutConfig.payment.adyenCc.icons[type]
: false : false
}, },
/**
*
* @returns {any}
*/
hasInstallments: function () { hasInstallments: function () {
return this.comboCardOption() === 'credit' && window.checkoutConfig.payment.adyenCc.hasInstallments; return this.comboCardOption() === 'credit' && window.checkoutConfig.payment.adyenCc.hasInstallments;
}, },
/**
*
* @returns {*}
*/
getAllInstallments: function () { getAllInstallments: function () {
return window.checkoutConfig.payment.adyenCc.installments; return window.checkoutConfig.payment.adyenCc.installments;
}, },
/**
* @returns {*|boolean}
*/
areComboCardsEnabled: function () { areComboCardsEnabled: function () {
if (quote.billingAddress() === null) { if (quote.billingAddress() === null) {
return false; return false;
...@@ -517,6 +437,9 @@ define( ...@@ -517,6 +437,9 @@ define(
setValidateHandler: function (handler) { setValidateHandler: function (handler) {
this.validateHandler = handler; this.validateHandler = handler;
}, },
/**
* @returns {exports}
*/
context: function () { context: function () {
return this; return this;
}, },
......
...@@ -29,21 +29,38 @@ define( ...@@ -29,21 +29,38 @@ define(
'Magento_Checkout/js/checkout-data', 'Magento_Checkout/js/checkout-data',
'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Checkout/js/model/payment/additional-validators',
'mage/storage', 'mage/storage',
'Magento_Checkout/js/model/url-builder',
'Adyen_Payment/js/model/adyen-payment-service', 'Adyen_Payment/js/model/adyen-payment-service',
'Magento_Checkout/js/model/url-builder',
'Magento_Customer/js/model/customer', 'Magento_Customer/js/model/customer',
'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/full-screen-loader',
'Magento_Checkout/js/action/place-order', 'Magento_Checkout/js/action/place-order',
'uiLayout', 'uiLayout',
'Magento_Ui/js/model/messages' 'Magento_Ui/js/model/messages',
'Adyen_Payment/js/bundle',
'Adyen_Payment/js/model/adyen-configuration'
], ],
function (ko, $, Component, selectPaymentMethodAction, quote, checkoutData, additionalValidators, storage, urlBuilder, adyenPaymentService, customer, fullScreenLoader, placeOrderAction, layout, Messages) { function (ko,
$,
Component,
selectPaymentMethodAction,
quote,
checkoutData,
additionalValidators,
storage,
adyenPaymentService,
urlBuilder,
customer,
fullScreenLoader,
placeOrderAction,
layout,
Messages,
AdyenComponent,
adyenConfiguration) {
'use strict'; 'use strict';
var brandCode = ko.observable(null); var brandCode = ko.observable(null);
var paymentMethod = ko.observable(null); var paymentMethod = ko.observable(null);
var messageComponents; var messageComponents;
var shippingAddressCountryCode = quote.shippingAddress().countryId; var unsupportedPaymentMethods = ['scheme', 'boleto', 'bcmc_mobile_QR', 'wechatpay', /^bcmc$/, "applepay", "paywithgoogle", "paypal"];
var unsupportedPaymentMethods = ['scheme', 'boleto', 'bcmc_mobile_QR', 'wechatpay', /^bcmc$/, "applepay", "paywithgoogle"];
/** /**
* Shareble adyen checkout component * Shareble adyen checkout component
* @type {AdyenCheckout} * @type {AdyenCheckout}
...@@ -54,21 +71,14 @@ define( ...@@ -54,21 +71,14 @@ define(
self: this, self: this,
defaults: { defaults: {
template: 'Adyen_Payment/payment/hpp-form', template: 'Adyen_Payment/payment/hpp-form',
brandCode: '' brandCode: '',
stateData: {}
}, },
initObservable: function () { initObservable: function () {
this._super() this._super()
.observe([ .observe([
'brandCode', 'brandCode',
'issuer', 'paymentListObservable'
'gender',
'dob',
'telephone',
'ownerName',
'ibanNumber',
'ssn',
'bankAccountNumber',
'bankLocationId'
]); ]);
return this; return this;
}, initialize: function () { }, initialize: function () {
...@@ -76,79 +86,55 @@ define( ...@@ -76,79 +86,55 @@ define(
var self = this; var self = this;
this._super(); this._super();
fullScreenLoader.startLoader(); var paymentMethodsObservable = adyenPaymentService.getPaymentMethodsObservable();
/** /**
* Create sherable checkout component * Create sherable checkout component
* @type {AdyenCheckout} * @type {AdyenCheckout}
*/ */
self.checkoutComponent = new AdyenCheckout({ self.checkoutComponent = adyenPaymentService.getCheckoutComponent();
locale: self.getLocale() self.setAdyenHppPaymentMethods();
});
// reset variable:
adyenPaymentService.setPaymentMethods();
adyenPaymentService.retrieveAvailablePaymentMethods(function () { paymentMethodsObservable.subscribe(function() {
var paymentMethods = adyenPaymentService.getAvailablePaymentMethods(); self.checkoutComponent = adyenPaymentService.getCheckoutComponent();
if (JSON.stringify(paymentMethods).indexOf("ratepay") > -1) { self.setAdyenHppPaymentMethods();
var ratePayId = window.checkoutConfig.payment.adyenHpp.ratePayId;
var dfValueRatePay = self.getRatePayDeviceIdentToken();
window.di = {
t: dfValueRatePay.replace(':', ''),
v: ratePayId,
l: 'Checkout'
};
// Load Ratepay script
var ratepayScriptTag = document.createElement('script');
ratepayScriptTag.src = "//d.ratepay.com/" + ratePayId + "/di.js";
ratepayScriptTag.type = "text/javascript";
document.body.appendChild(ratepayScriptTag);
}
// create component needs to be in initialize method
var messageComponents = {};
_.map(paymentMethods, function (value) {
var messageContainer = new Messages();
var name = 'messages-' + self.getBrandCodeFromPaymentMethod(value);
var messagesComponent = {
parent: self.name,
name: 'messages-' + self.getBrandCodeFromPaymentMethod(value),
displayArea: 'messages-' + self.getBrandCodeFromPaymentMethod(value),
component: 'Magento_Ui/js/view/messages',
config: {
messageContainer: messageContainer
}
};
layout([messagesComponent]);
messageComponents[name] = messageContainer;
});
self.messageComponents = messageComponents;
fullScreenLoader.stopLoader();
}); });
}, },
getAdyenHppPaymentMethods: function () { getAdyenHppPaymentMethods: function () {
return this.paymentListObservable;
},
setAdyenHppPaymentMethods: function () {
var self = this; var self = this;
var currentShippingAddressCountryCode = quote.shippingAddress().countryId;
// retrieve new payment methods if country code changed
if (shippingAddressCountryCode != currentShippingAddressCountryCode) {
fullScreenLoader.startLoader();
adyenPaymentService.retrieveAvailablePaymentMethods();
shippingAddressCountryCode = currentShippingAddressCountryCode;
fullScreenLoader.stopLoader();
}
var paymentMethods = adyenPaymentService.getAvailablePaymentMethods(); fullScreenLoader.startLoader();
var paymentMethods = self.checkoutComponent.paymentMethodsResponse.paymentMethods;
// create component needs to be in initialize method
var messageComponents = {};
_.map(paymentMethods, function (value) {
var messageContainer = new Messages();
var name = 'messages-' + self.getBrandCodeFromPaymentMethod(value);
var messagesComponent = {
parent: self.name,
name: 'messages-' + self.getBrandCodeFromPaymentMethod(value),
displayArea: 'messages-' + self.getBrandCodeFromPaymentMethod(value),
component: 'Magento_Ui/js/view/messages',
config: {
messageContainer: messageContainer
}
};
layout([messagesComponent]);
messageComponents[name] = messageContainer;
});
var paymentList = _.reduce(paymentMethods, function (accumulator, value) { self.messageComponents = messageComponents;
if (!self.isPaymentMethodSupported(value.type)) { // Iterate through the payment methods and render them
var paymentList = _.reduce(paymentMethods, function (accumulator, paymentMethod) {
if (!self.isPaymentMethodSupported(paymentMethod.type)) {
return accumulator; return accumulator;
} }
...@@ -159,11 +145,11 @@ define( ...@@ -159,11 +145,11 @@ define(
* @returns {*} * @returns {*}
*/ */
result.getBrandCode = function () { result.getBrandCode = function () {
return self.getBrandCodeFromPaymentMethod(value); return self.getBrandCodeFromPaymentMethod(paymentMethod);
}; };
result.value = result.getBrandCode(); result.brandCode = result.getBrandCode();
result.name = value; result.name = paymentMethod.name;
result.method = self.item.method; result.method = self.item.method;
/** /**
* Observable to enable and disable place order buttons for payment methods * Observable to enable and disable place order buttons for payment methods
...@@ -195,333 +181,72 @@ define( ...@@ -195,333 +181,72 @@ define(
result.afterPlaceOrder = function () { result.afterPlaceOrder = function () {
return self.afterPlaceOrder(); return self.afterPlaceOrder();
}; };
/**
* Checks if payment method is open invoice
* @returns {*|isPaymentMethodOpenInvoiceMethod}
*/
result.isPaymentMethodOpenInvoiceMethod = function () {
return value.isPaymentMethodOpenInvoiceMethod;
};
/**
* Checks if payment method is open invoice but not in the list below
* [klarna, afterpay]
* @returns {boolean}
*/
result.isPaymentMethodOtherOpenInvoiceMethod = function () {
if (
!result.isPaymentMethodAfterPay() &&
!result.isPaymentMethodKlarna() &&
!result.isPaymentMethodAfterPayTouch() &&
value.isPaymentMethodOpenInvoiceMethod
) {
return true;
}
return false;
};
/**
* Checks if payment method is klarna
* @returns {boolean}
*/
result.isPaymentMethodKlarna = function () {
if (result.getBrandCode() === "klarna") {
return true;
}
return false;
};
/**
* Checks if payment method is after pay
* @returns {boolean}
*/
result.isPaymentMethodAfterPay = function () {
if (result.getBrandCode() === "afterpay_default") {
return true;
}
return false;
};
/**
* Checks if payment method is after pay touch
* @returns {boolean}
*/
result.isPaymentMethodAfterPayTouch = function () {
if (result.getBrandCode() === "afterpaytouch") {
return true;
}
return false;
};
/**
* Get personal number (SSN) length based on the buyer's country
* @returns {number}
*/
result.getSsnLength = function () {
if (quote.billingAddress().countryId == "NO") {
//14 digits for Norway ÅÅÅÅMMDD-XXXXX
return 14;
} else {
//13 digits for other Nordic countries ÅÅÅÅMMDD-XXXX
return 13;
}
};
/**
* Get max length for the Bank account number
*/
result.getBankAccountNumberMaxLength = function () {
return 17;
};
/**
* Finds the issuer property in the payment method's response and if available returns it's index
* @returns
*/
result.findIssuersProperty = function () {
var issuerKey = false;
if (typeof value.details !== 'undefined') {
$.each(value.details, function (key, detail) {
if (typeof detail.items !== 'undefined' && detail.key == 'issuer') {
issuerKey = key;
}
});
}
return issuerKey;
}
/**
* Checks if the payment method has issuers property available
* @returns {boolean}
*/
result.hasIssuersProperty = function () {
if (result.findIssuersProperty() !== false) {
return true;
}
return false;
};
/**
* Checks if the payment method has issuer(s) available
* @returns {boolean}
*/
result.hasIssuersAvailable = function () {
if (result.hasIssuersProperty() && value.details[result.findIssuersProperty()].items.length > 0) {
return true;
}
return false;
};
/**
* Returns the issuers for a payment method
* @returns {*}
*/
result.getIssuers = function () {
if (result.hasIssuersAvailable()) {
return value.details[result.findIssuersProperty()].items;
}
return [];
};
/**
* Checks if payment method is iDeal
* @returns {boolean}
*/
result.isIdeal = function () {
if (result.getBrandCode().indexOf("ideal") >= 0) {
return true;
}
return false;
};
/**
* Checks if payment method is ACH
* @returns {boolean}
*/
result.isAch = function () {
if (result.getBrandCode().indexOf("ach") == 0) {
return true;
}
return false;
};
/**
* Checks if payment method is sepa direct debit
*/
result.isSepaDirectDebit = function () {
if (result.getBrandCode().indexOf("sepadirectdebit") >= 0) {
return true;
}
return false;
};
/** /**
* Renders the secure fields, * Renders the secure fields,
* creates the ideal component, * creates the ideal component,
* sets up the callbacks for ideal components and * sets up the callbacks for ideal components and
*/ */
result.renderIdealComponent = function () { result.renderCheckoutComponent = function () {
result.isPlaceOrderAllowed(false); result.isPlaceOrderAllowed(false);
var idealNode = document.getElementById('iDealContainer'); var showPayButton = false;
const showPayButtonPaymentMethods = [
'paypal'
];
var ideal = self.checkoutComponent.create('ideal', { if (showPayButtonPaymentMethods.includes(paymentMethod.type)) {
items: result.getIssuers(), showPayButton = true;
onChange: function (state) { }
if (!!state.isValid) {
result.issuer(state.data.paymentMethod.issuer);
result.isPlaceOrderAllowed(true);
} else {
result.isPlaceOrderAllowed(false);
}
}
});
ideal.mount(idealNode);
};
/**
* Creates the sepa direct debit component,
* sets up the callbacks for sepa components
*/
result.renderSepaDirectDebitComponent = function () {
result.isPlaceOrderAllowed(false);
var sepaDirectDebitNode = document.getElementById('sepaDirectDebitContainer');
var sepaDirectDebit = self.checkoutComponent.create('sepadirectdebit', {
countryCode: self.getLocale(),
onChange: function (state) {
if (!!state.isValid) {
result.ownerName(state.data.paymentMethod["sepa.ownerName"]);
result.ibanNumber(state.data.paymentMethod["sepa.ibanNumber"]);
result.isPlaceOrderAllowed(true);
} else {
result.isPlaceOrderAllowed(false);
}
}
});
sepaDirectDebit.mount(sepaDirectDebitNode);
};
/**
* Creates the klarna component,
* sets up the callbacks for klarna components
*/
result.renderKlarnaComponent = function () {
/* The new Klarna integration doesn't return details and the component does not handle it */ // If the details are empty and the pay button does not needs to be rendered by the component
if (!value.details) { // simply skip rendering the adyen checkout component
if (!paymentMethod.details && !showPayButton) {
result.isPlaceOrderAllowed(true);
return; return;
} }
var klarnaNode = document.getElementById('klarnaContainer'); /*Use the storedPaymentMethod object and the custom onChange function as the configuration object together*/
var configuration = {
var klarna = self.checkoutComponent.create('klarna', { showPayButton: showPayButton,
countryCode: self.getLocale(), data: {
details: self.filterOutOpenInvoiceComponentDetails(value.details), billingAddress: {
visibility: { city: quote.shippingAddress().city,
personalDetails: "editable" country: quote.shippingAddress().countryId,
}, houseNumberOrName: '',
onChange: function (state) { postalCode: quote.shippingAddress().postcode,
if (!!state.isValid) { street: quote.shippingAddress().street.join(" ")
result.dob(state.data.paymentMethod.personalDetails.dateOfBirth);
result.telephone(state.data.paymentMethod.personalDetails.telephoneNumber);
result.gender(state.data.paymentMethod.personalDetails.gender);
result.isPlaceOrderAllowed(true);
} else {
result.isPlaceOrderAllowed(false);
} }
}
}).mount(klarnaNode);
};
/**
* Creates the afterpay component,
* sets up the callbacks for klarna components
*/
result.renderAfterPayComponent = function () {
var afterPay = self.checkoutComponent.create('afterpay', {
countryCode: self.getLocale(),
details: self.filterOutOpenInvoiceComponentDetails(value.details),
visibility: {
personalDetails: "editable"
}, },
onChange: function (state) { onChange: function (state) {
if (!!state.isValid) { if (!!state.isValid) {
result.dob(state.data.paymentMethod.personalDetails.dateOfBirth); result.stateData = state.data;
result.telephone(state.data.paymentMethod.personalDetails.telephoneNumber);
result.gender(state.data.paymentMethod.personalDetails.gender);
result.isPlaceOrderAllowed(true); result.isPlaceOrderAllowed(true);
} else { } else {
result.stateData = {};
result.isPlaceOrderAllowed(false); result.isPlaceOrderAllowed(false);
} }
} }
}).mount(document.getElementById('afterPayContainer')); };
};
if (result.hasIssuersProperty()) { try {
if (!result.hasIssuersAvailable()) { self.checkoutComponent.create(result.getBrandCode(), configuration).mount('#adyen-alternative-payment-container-' + result.getBrandCode());
return false; } catch (err) {
// The component does not exist yet
} }
};
result.issuerIds = result.getIssuers(); result.getRatePayDeviceIdentToken = function () {
result.issuer = ko.observable(null); return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
} else if (value.isPaymentMethodOpenInvoiceMethod) { };
result.telephone = ko.observable(quote.shippingAddress().telephone);
result.gender = ko.observable(window.checkoutConfig.payment.adyenHpp.gender);
result.dob = ko.observable(window.checkoutConfig.payment.adyenHpp.dob);
result.datepickerValue = ko.observable(); // needed ??
result.ssn = ko.observable();
result.getRatePayDeviceIdentToken = function () {
return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
};
result.showSsn = function () {
if (result.getBrandCode().indexOf("klarna") >= 0) {
var ba = quote.billingAddress();
if (ba != null) {
var nordicCountriesList = window.checkoutConfig.payment.adyenHpp.nordicCountries;
if (nordicCountriesList.indexOf(ba.countryId) >= 0) {
return true;
}
}
}
return false;
};
} else if (result.isSepaDirectDebit()) {
result.ownerName = ko.observable(null);
result.ibanNumber = ko.observable(null);
} else if (result.isAch()) {
result.ownerName = ko.observable(null);
result.bankAccountNumber = ko.observable(null);
result.bankLocationId = ko.observable(null);
}
accumulator.push(result); accumulator.push(result);
return accumulator; return accumulator;
}, []); }, []);
return paymentList; self.paymentListObservable(paymentList);
}, fullScreenLoader.stopLoader();
/**
* Some payment methods we do not want to render as it requires extra implementation
* or is already implemented in a separate payment method.
* Using a match as we want to prevent to render all Boleto and most of the WeChat types
* @param paymentMethod
* @returns {boolean}
*/
isPaymentMethodSupported: function (paymentMethod) {
if (paymentMethod == 'wechatpayWeb') {
return true;
}
for (var i = 0; i < unsupportedPaymentMethods.length; i++) {
var match = paymentMethod.match(unsupportedPaymentMethods[i]);
if (match) {
return false;
}
}
return true;
}, },
// TODO prefill gender in components where it is available
getGenderTypes: function () { getGenderTypes: function () {
return _.map(window.checkoutConfig.payment.adyenHpp.genderTypes, function (value, key) { return _.map(window.checkoutConfig.payment.adyenHpp.genderTypes, function (value, key) {
return { return {
...@@ -539,25 +264,11 @@ define( ...@@ -539,25 +264,11 @@ define(
data.method = self.method; data.method = self.method;
var additionalData = {}; var additionalData = {};
additionalData.brand_code = self.value; additionalData.brand_code = self.brandCode;
additionalData.state_data = JSON.stringify(self.stateData);
if (self.hasIssuersAvailable()) {
additionalData.issuer_id = this.issuer(); if (brandCode() == "ratepay") {
} else if (self.isPaymentMethodOpenInvoiceMethod()) { additionalData.df_value = this.getRatePayDeviceIdentToken();
additionalData.gender = this.gender();
additionalData.dob = this.dob();
additionalData.telephone = this.telephone();
additionalData.ssn = this.ssn();
if (brandCode() == "ratepay") {
additionalData.df_value = this.getRatePayDeviceIdentToken();
}
} else if (self.isSepaDirectDebit()) {
additionalData.ownerName = this.ownerName();
additionalData.ibanNumber = this.ibanNumber();
} else if (self.isAch()) {
additionalData.bankAccountOwnerName = this.ownerName();
additionalData.bankAccountNumber = this.bankAccountNumber();
additionalData.bankLocationId = this.bankLocationId();
} }
data.additional_data = additionalData; data.additional_data = additionalData;
...@@ -566,26 +277,16 @@ define( ...@@ -566,26 +277,16 @@ define(
return false; return false;
}, },
selectPaymentMethodBrandCode: function () {
var self = this;
// set payment method to adyen_hpp
var data = {
"method": self.method,
"po_number": null,
"additional_data": {
brand_code: self.value
}
};
// set the brandCode
brandCode(self.value);
// set payment method // DEFAULT FUNCTIONS
paymentMethod(self.method); validate: function (brandCode) {
var form = '#payment_form_' + this.getCode() + '_' + brandCode;
var validate = $(form).validation() && $(form).validation('isValid');
selectPaymentMethodAction(data); if (!validate) {
checkoutData.setSelectedPaymentMethod(self.method); return false;
}
return true; return true;
}, },
...@@ -628,8 +329,48 @@ define( ...@@ -628,8 +329,48 @@ define(
} }
) )
}, },
isBrandCodeChecked: ko.computed(function () {
/**
*
* @returns {boolean}
*/
selectPaymentMethodBrandCode: function () {
var self = this;
// set payment method to adyen_hpp
var data = {
"method": self.method,
"po_number": null,
"additional_data": {
brand_code: self.brandCode
}
};
// set the brandCode
brandCode(self.brandCode);
// set payment method
paymentMethod(self.method);
selectPaymentMethodAction(data);
checkoutData.setSelectedPaymentMethod(self.method);
return true;
},
// CONFIGURATIONS
isIconEnabled: function () {
return window.checkoutConfig.payment.adyen.showLogo;
},
getRatePayDeviceIdentToken: function () {
return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
},
/**
*
*/
isBrandCodeChecked: ko.computed(function () {
if (!quote.paymentMethod()) { if (!quote.paymentMethod()) {
return null; return null;
} }
...@@ -637,19 +378,27 @@ define( ...@@ -637,19 +378,27 @@ define(
if (quote.paymentMethod().method == paymentMethod()) { if (quote.paymentMethod().method == paymentMethod()) {
return brandCode(); return brandCode();
} }
return null; return null;
}), }),
isIconEnabled: function () {
return window.checkoutConfig.payment.adyen.showLogo;
},
validate: function (brandCode) {
var form = '#payment_form_' + this.getCode() + '_' + brandCode;
var validate = $(form).validation() && $(form).validation('isValid');
if (!validate) { /**
return false; * Some payment methods we do not want to render as it requires extra implementation
* or is already implemented in a separate payment method.
* Using a match as we want to prevent to render all Boleto and most of the WeChat types
* @param paymentMethod
* @returns {boolean}
*/
isPaymentMethodSupported: function (paymentMethod) {
if (paymentMethod == 'wechatpayWeb') {
return true;
}
for (var i = 0; i < unsupportedPaymentMethods.length; i++) {
var match = paymentMethod.match(unsupportedPaymentMethods[i]);
if (match) {
return false;
}
} }
return true; return true;
}, },
/** /**
...@@ -663,52 +412,6 @@ define( ...@@ -663,52 +412,6 @@ define(
} }
return ''; return '';
},
getRatePayDeviceIdentToken: function () {
return window.checkoutConfig.payment.adyenHpp.deviceIdentToken;
},
getLocale: function () {
return window.checkoutConfig.payment.adyenHpp.locale;
},
/**
* In the open invoice components we need to validate only the personal details and only the
* dateOfBirth, telephoneNumber and gender if it's set in the admin
* @param details
* @returns {Array}
*/
filterOutOpenInvoiceComponentDetails: function (details) {
var self = this;
var filteredDetails = _.map(details, function (parentDetail) {
if (parentDetail.key == "personalDetails") {
var detailObject = _.map(parentDetail.details, function (detail) {
if (detail.key == 'dateOfBirth' ||
detail.key == 'telephoneNumber' ||
detail.key == 'gender') {
return detail;
}
});
if (!!detailObject) {
return {
"key": parentDetail.key,
"type": parentDetail.type,
"details": self.filterUndefinedItemsInArray(detailObject)
};
}
}
});
return self.filterUndefinedItemsInArray(filteredDetails);
},
/**
* Helper function to filter out the undefined items from an array
* @param arr
* @returns {*}
*/
filterUndefinedItemsInArray: function (arr) {
return arr.filter(function (item) {
return typeof item !== 'undefined';
});
} }
}); });
} }
......
...@@ -33,15 +33,15 @@ define( ...@@ -33,15 +33,15 @@ define(
'uiLayout', 'uiLayout',
'Magento_Ui/js/model/messages', 'Magento_Ui/js/model/messages',
'mage/url', 'mage/url',
'Adyen_Payment/js/threeds2-js-utils',
'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/full-screen-loader',
'Magento_Paypal/js/action/set-payment-method', 'Magento_Paypal/js/action/set-payment-method',
'Magento_Checkout/js/model/url-builder', 'Magento_Checkout/js/model/url-builder',
'mage/storage', 'mage/storage',
'Magento_Checkout/js/action/place-order', 'Magento_Checkout/js/action/place-order',
'Adyen_Payment/js/model/threeds2',
'Magento_Checkout/js/model/error-processor', 'Magento_Checkout/js/model/error-processor',
'Adyen_Payment/js/model/adyen-payment-service' 'Adyen_Payment/js/model/adyen-payment-service',
'Adyen_Payment/js/bundle',
'Adyen_Payment/js/model/adyen-configuration'
], ],
function ( function (
ko, ko,
...@@ -56,17 +56,16 @@ define( ...@@ -56,17 +56,16 @@ define(
layout, layout,
Messages, Messages,
url, url,
threeDS2Utils,
fullScreenLoader, fullScreenLoader,
setPaymentMethodAction, setPaymentMethodAction,
urlBuilder, urlBuilder,
storage, storage,
placeOrderAction, placeOrderAction,
threeds2,
errorProcessor, errorProcessor,
adyenPaymentService adyenPaymentService,
adyenComponentBundle,
adyenConfiguration
) { ) {
'use strict'; 'use strict';
var messageComponents; var messageComponents;
...@@ -74,7 +73,6 @@ define( ...@@ -74,7 +73,6 @@ define(
var recurringDetailReference = ko.observable(null); var recurringDetailReference = ko.observable(null);
var variant = ko.observable(null); var variant = ko.observable(null);
var paymentMethod = ko.observable(null); var paymentMethod = ko.observable(null);
var numberOfInstallments = ko.observable(null);
var isValid = ko.observable(false); var isValid = ko.observable(false);
return Component.extend({ return Component.extend({
...@@ -83,16 +81,15 @@ define( ...@@ -83,16 +81,15 @@ define(
template: 'Adyen_Payment/payment/oneclick-form', template: 'Adyen_Payment/payment/oneclick-form',
recurringDetailReference: '', recurringDetailReference: '',
variant: '', variant: '',
numberOfInstallments: '' checkoutComponent: {},
storedPayments: []
}, },
initObservable: function () { initObservable: function () {
this._super() this._super()
.observe([ .observe([
'recurringDetailReference', 'recurringDetailReference',
'creditCardType', 'creditCardType',
'encryptedCreditCardVerificationNumber', 'variant'
'variant',
'numberOfInstallments'
]); ]);
return this; return this;
}, },
...@@ -100,17 +97,20 @@ define( ...@@ -100,17 +97,20 @@ define(
var self = this; var self = this;
this._super(); this._super();
this.checkoutComponent = adyenPaymentService.getCheckoutComponent();
this.storedPayments = this.checkoutComponent.paymentMethodsResponse.storedPaymentMethods;
// create component needs to be in initialize method // create component needs to be in initialize method
var messageComponents = {}; var messageComponents = {};
_.map(window.checkoutConfig.payment.adyenOneclick.billingAgreements, function (value) { _.map(this.storedPayments, function (storedPayment) {
var messageContainer = new Messages(); var messageContainer = new Messages();
var name = 'messages-' + value.reference_id; var name = 'messages-' + storedPayment.id;
var messagesComponent = { var messagesComponent = {
parent: self.name, parent: self.name,
name: 'messages-' + value.reference_id, name: 'messages-' + storedPayment.id,
// name: self.name + '.messages', // name: self.name + '.messages',
displayArea: 'messages-' + value.reference_id, displayArea: 'messages-' + storedPayment.id,
component: 'Magento_Ui/js/view/messages', component: 'Magento_Ui/js/view/messages',
config: { config: {
messageContainer: messageContainer messageContainer: messageContainer
...@@ -128,48 +128,12 @@ define( ...@@ -128,48 +128,12 @@ define(
* *
* @returns {Array} * @returns {Array}
*/ */
getAdyenBillingAgreements: function () { getAdyenStoredPayments: function () {
var self = this; var self = this;
// shareable adyen checkout component
var checkout = new AdyenCheckout({
locale: self.getLocale(),
originKey: self.getOriginKey(),
environment: self.getCheckoutEnvironment(),
risk: {
enabled: false
}
});
// convert to list so you can iterate // convert to list so you can iterate
var paymentList = _.map(window.checkoutConfig.payment.adyenOneclick.billingAgreements, function (value) { var paymentList = _.map(this.storedPayments, function (storedPayment) {
var messageContainer = self.messageComponents['messages-' + storedPayment.id];
var creditCardExpMonth, creditCardExpYear = false;
if (value.agreement_data.card) {
creditCardExpMonth = value.agreement_data.card.expiryMonth;
creditCardExpYear = value.agreement_data.card.expiryYear;
}
// pre-define installments if they are set
var i, installments = [];
var grandTotal = quote.totals().grand_total;
var dividedString = "";
var dividedAmount = 0;
if (value.number_of_installments) {
for (i = 0; i < value.number_of_installments.length; i++) {
dividedAmount = (grandTotal / value.number_of_installments[i]).toFixed(quote.getPriceFormat().precision);
dividedString = value.number_of_installments[i] + " x " + dividedAmount + " " + quote.totals().quote_currency_code;
installments.push({
key: [dividedString],
value: value.number_of_installments[i]
});
}
}
var messageContainer = self.messageComponents['messages-' + value.reference_id];
// for recurring enable the placeOrder button at all times // for recurring enable the placeOrder button at all times
var placeOrderAllowed = true; var placeOrderAllowed = true;
...@@ -180,21 +144,18 @@ define( ...@@ -180,21 +144,18 @@ define(
isValid(true); isValid(true);
} }
var agreementLabel = storedPayment.name + ', ' + storedPayment.holderName + ', **** ' + storedPayment.lastFour;
return { return {
'label': value.agreement_label, 'label': agreementLabel,
'value': value.reference_id, 'value': storedPayment.storedPaymentMethodId,
'agreement_data': value.agreement_data, 'brand': storedPayment.brand,
'logo': value.logo, 'logo': {},
'installment': '', 'installment': '',
'number_of_installments': value.number_of_installments,
'method': self.item.method, 'method': self.item.method,
'encryptedCreditCardVerificationNumber': '', 'encryptedCreditCardVerificationNumber': '',
'creditCardExpMonth': ko.observable(creditCardExpMonth),
'creditCardExpYear': ko.observable(creditCardExpYear),
'getInstallments': ko.observableArray(installments),
'placeOrderAllowed': ko.observable(placeOrderAllowed), 'placeOrderAllowed': ko.observable(placeOrderAllowed),
checkoutComponent: self.checkoutComponent,
isButtonActive: function () { isButtonActive: function () {
return self.isActive() && this.getCode() == self.isChecked() && self.isBillingAgreementChecked() && this.placeOrderAllowed() && self.isPlaceOrderActionAllowed(); return self.isActive() && this.getCode() == self.isChecked() && self.isBillingAgreementChecked() && this.placeOrderAllowed() && self.isPlaceOrderActionAllowed();
}, },
...@@ -213,13 +174,6 @@ define( ...@@ -213,13 +174,6 @@ define(
if (event) { if (event) {
event.preventDefault(); event.preventDefault();
} }
// only use installments for cards
if (self.agreement_data.card) {
if (self.hasVerification()) {
var options = {enableValidations: false};
}
numberOfInstallments(self.installment);
}
if (this.validate() && additionalValidators.validate()) { if (this.validate() && additionalValidators.validate()) {
fullScreenLoader.startLoader(); fullScreenLoader.startLoader();
...@@ -245,67 +199,37 @@ define( ...@@ -245,67 +199,37 @@ define(
}, },
/** /**
* Renders the secure CVC field, * Renders the stored payment component,
* creates the card component,
* sets up the callbacks for card components
*/ */
renderSecureCVC: function () { renderStoredPaymentComponent: function () {
var self = this; var self = this;
if (!self.getOriginKey()) { if (!adyenConfiguration.getOriginKey()) {
return; return;
} }
var oneClickCardNode = document.getElementById('cvcContainer-' + self.value);
// this should be fixed in new version of checkout card component
var hideCVC = false; var hideCVC = false;
if (this.hasVerification()) { if (!this.hasVerification()) {
if (self.agreement_data.variant == "maestro") {
// for maestro cvc is optional
self.placeOrderAllowed(true);
}
} else {
hideCVC = true; hideCVC = true;
} }
var oneClickCard = checkout /*Use the storedPaymentMethod object and the custom onChange function as the configuration object together*/
.create('card', { var configuration = Object.assign(storedPayment, {
type: self.agreement_data.variant, hideCVC: hideCVC,
hideCVC: hideCVC, 'onChange': function (state) {
details: self.getOneclickDetails(), if (!!state.isValid) {
storedDetails: { self.stateData = state.data;
"card": { self.placeOrderAllowed = true;
"expiryMonth": self.agreement_data.card.expiryMonth, } else {
"expiryYear": self.agreement_data.card.expiryYear, self.placeOrderAllowed = false;
"holderName": self.agreement_data.card.holderName, self.stateData = {};
"number": self.agreement_data.card.number
}
},
onChange: function (state, component) {
if (state.isValid) {
self.placeOrderAllowed(true);
isValid(true);
if (typeof state.data !== 'undefined' &&
typeof state.data.paymentMethod !== 'undefined' &&
typeof state.data.paymentMethod.encryptedSecurityCode !== 'undefined'
) {
self.encryptedCreditCardVerificationNumber = state.data.paymentMethod.encryptedSecurityCode;
}
} else {
self.encryptedCreditCardVerificationNumber = '';
if (self.agreement_data.variant != "maestro") {
self.placeOrderAllowed(false);
isValid(false);
}
}
} }
}) }
.mount(oneClickCardNode); });
window.adyencheckout = oneClickCard; self.checkoutComponent
.create(storedPayment.type, configuration)
.mount('#storedPaymentContainer-' + self.value);
}, },
/** /**
* Based on the response we can start a 3DS2 validation or place the order * Based on the response we can start a 3DS2 validation or place the order
...@@ -344,7 +268,7 @@ define( ...@@ -344,7 +268,7 @@ define(
onComplete: function (result) { onComplete: function (result) {
var request = result.data; var request = result.data;
request.orderId = orderId; request.orderId = orderId;
threeds2.processThreeDS2(request).done(function (responseJSON) { adyenPaymentService.processThreeDS2(request).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId) self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
}).fail(function (result) { }).fail(function (result) {
errorProcessor.process(result, self.getMessageContainer()); errorProcessor.process(result, self.getMessageContainer());
...@@ -380,7 +304,7 @@ define( ...@@ -380,7 +304,7 @@ define(
fullScreenLoader.startLoader(); fullScreenLoader.startLoader();
var request = result.data; var request = result.data;
request.orderId = orderId; request.orderId = orderId;
threeds2.processThreeDS2(request).done(function (responseJSON) { adyenPaymentService.processThreeDS2(request).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId) self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
}).fail(function (result) { }).fail(function (result) {
errorProcessor.process(result, self.getMessageContainer()); errorProcessor.process(result, self.getMessageContainer());
...@@ -396,50 +320,18 @@ define( ...@@ -396,50 +320,18 @@ define(
self.threeDS2Component.mount(threeDS2Node); 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.
* When we render the stored payments dynamically from the paymentMethods call response it
* should be removed
* @returns {*}
*/
getOneclickDetails: function () {
var self = this;
if (self.agreement_data.variant === 'bcmc') {
return [];
} else {
return [
{
"key": "cardDetails.cvc",
"type": "cvc"
}
];
}
},
/** /**
* Builds the payment details part of the payment information reqeust * Builds the payment details part of the payment information reqeust
* *
* @returns {{method: *, additional_data: {variant: *, recurring_detail_reference: *, number_of_installments: *, cvc: (string|*), expiryMonth: *, expiryYear: *}}} * @returns {{additional_data: {state_data: string}, method: *}}
*/ */
getData: function () { getData: function () {
var self = this; var self = this;
var browserInfo = threeDS2Utils.getBrowserInfo();
return { return {
"method": self.method, "method": self.method,
additional_data: { additional_data: {
variant: variant(), 'state_data': JSON.stringify(this.stateData),
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
} }
}; };
}, },
...@@ -467,13 +359,13 @@ define( ...@@ -467,13 +359,13 @@ define(
return self.hasVerification() return self.hasVerification()
}, },
getMessageName: function () { getMessageName: function () {
return 'messages-' + value.reference_id; return 'messages-' + storedPayment.id;
}, },
getMessageContainer: function () { getMessageContainer: function () {
return messageContainer; return messageContainer;
}, },
getOriginKey: function () { getOriginKey: function () {
return self.getOriginKey(); return adyenConfiguration.getOriginKey();
}, },
isPlaceOrderActionAllowed: function () { isPlaceOrderActionAllowed: function () {
return self.isPlaceOrderActionAllowed(); // needed for placeOrder method return self.isPlaceOrderActionAllowed(); // needed for placeOrder method
...@@ -510,7 +402,7 @@ define( ...@@ -510,7 +402,7 @@ define(
// set the brandCode // set the brandCode
recurringDetailReference(self.value); recurringDetailReference(self.value);
variant(self.agreement_data.variant); variant(self.brand);
// set payment method // set payment method
paymentMethod(self.method); paymentMethod(self.method);
...@@ -554,24 +446,17 @@ define( ...@@ -554,24 +446,17 @@ define(
context: function () { context: function () {
return this; return this;
}, },
canCreateBillingAgreement: function () { //TODO create configuration for this on admin
return window.checkoutConfig.payment.adyenCc.canCreateBillingAgreement;
},
isShowLegend: function () { isShowLegend: function () {
return true; return true;
}, },
//TODO create a configuration for information on admin
getLegend: function () {
return '';
},
hasVerification: function () { hasVerification: function () {
return window.checkoutConfig.payment.adyenOneclick.hasCustomerInteraction; return window.checkoutConfig.payment.adyenOneclick.hasCustomerInteraction;
}, },
getLocale: function () {
return window.checkoutConfig.payment.adyenOneclick.locale;
},
getOriginKey: function () {
return window.checkoutConfig.payment.adyenOneclick.originKey;
},
getCheckoutEnvironment: function () {
return window.checkoutConfig.payment.adyenOneclick.checkoutEnvironment;
}
}); });
} }
); );
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
<!-- /ko --> <!-- /ko -->
<div class="field number cardContainerField"> <div class="field number cardContainerField">
<div class="checkout-component-dock" afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div> <div class="checkout-component-dock" afterRender="renderCardComponent()" data-bind="attr: { id: 'cardContainer'}"></div>
</div> </div>
<div id="threeDS2Wrapper"> <div id="threeDS2Wrapper">
...@@ -101,34 +101,6 @@ ...@@ -101,34 +101,6 @@
</div> </div>
</div> </div>
<!-- ko if: (hasInstallments())-->
<div class="field required"
data-bind="attr: {id: getCode() + '_installments_div'}, visible: installments().length > 0">
<label data-bind="attr: {for: getCode() + '_installments'}" class="label">
<span><!-- ko text: $t('Installments')--><!-- /ko --></span>
</label>
<div class="control">
<select class="select"
name="payment[number_of_installments]"
data-bind="attr: {id: getCode() + '_installments', 'data-container': getCode() + '-installments', 'data-validate': JSON.stringify({required:false})},
enable: isActive($parents),
options: installments,
optionsValue: 'value',
optionsText: 'key',
optionsCaption: $t('Do not use Installments'),
value: installment"
data-validate="{required:true}">
</select>
</div>
</div>
<!-- /ko -->
<!-- ko if: (isVaultEnabled())--> <!-- ko if: (isVaultEnabled())-->
<div class="field choice"> <div class="field choice">
<input type="checkbox" <input type="checkbox"
......
...@@ -23,24 +23,24 @@ ...@@ -23,24 +23,24 @@
--> -->
<!-- ko foreach: getAdyenHppPaymentMethods() --> <!-- ko foreach: getAdyenHppPaymentMethods() -->
<div class="payment-method" data-bind="css: {'_active': (value == $parent.isBrandCodeChecked())}"> <div class="payment-method" data-bind="css: {'_active': (brandCode == $parent.isBrandCodeChecked())}">
<div class="payment-method-title field choice"> <div class="payment-method-title field choice">
<input type="radio" <input type="radio"
name="payment[method]" name="payment[method]"
class="radio" class="radio"
data-bind="attr: {'id': value}, value: value, checked: $parent.isBrandCodeChecked, click: $parent.selectPaymentMethodBrandCode"/> data-bind="attr: {'id': 'adyen_' + brandCode}, value: 'adyen_' + brandCode, checked: brandCode == $parent.isBrandCodeChecked, click: $parent.selectPaymentMethodBrandCode"/>
<label data-bind="attr: {'for': value}" class="label"> <label data-bind="attr: {'for': 'adyen_' + brandCode}" class="label">
<!-- ko if: name.icon --> <!-- ko if: name.icon -->
<img data-bind="attr: { <img data-bind="attr: {
'src': name.icon.url, 'src': icon.url,
'width': name.icon.url.width, 'width': icon.url,
'height': name.icon.url.height 'height': icon.height
}"> }">
<!--/ko--> <!--/ko-->
<span data-bind="text: name.title"></span> <span data-bind="text: name"></span>
</label> </label>
</div> </div>
<div class="payment-method-content"> <div class="payment-method-content">
...@@ -51,244 +51,13 @@ ...@@ -51,244 +51,13 @@
<!--/ko--> <!--/ko-->
</div> </div>
<form class="form" data-role="adyen-hpp-form" action="#" method="post" data-bind="mageInit: { 'validation':[]}, attr: {id: 'payment_form_' + $parent.getCode() + '_' + value}"> <form class="form" data-role="adyen-hpp-form" action="#" method="post" data-bind="mageInit: { 'validation':[]}, attr: {id: 'payment_form_' + $parent.getCode() + '_' + brandCode}">
<fieldset class="fieldset" data-bind='attr: {id: "payment_fieldset_" + $parent.getCode() + "_" + value}'> <fieldset class="fieldset" data-bind='attr: {id: "payment_fieldset_" + $parent.getCode() + "_" + brandCode}'>
<!-- ko if: hasIssuersAvailable() --> <div data-bind='attr: {id: "adyen-alternative-payment-container-" + brandCode}'
<!-- ko if: isIdeal() --> afterRender="renderCheckoutComponent()"></div>
<div class="checkout-component-dock" afterRender="renderIdealComponent()" data-bind="attr: { id: 'iDealContainer'}"></div>
<!--/ko-->
<!-- ko ifnot: isIdeal() -->
<label data-bind="attr: {'for': 'issuerId'}" class="label">
<span><!-- ko text: $t('Select Your Bank') --><!-- /ko --></span>
</label>
<div class="field">
<select name="payment[issuer_id]" data-bind="
options: getIssuers(),
optionsText: 'name',
optionsValue: 'id',
value: issuer,
optionsCaption: $t('Choose Your Bank')">
</select>
</div>
<!--/ko-->
<!--/ko-->
<!-- ko if: isPaymentMethodKlarna() -->
<!-- ko if: showSsn() -->
<div class="field ssn type required">
<label data-bind="attr: {for: getCode() + '_ssn_' + value}" class="adyen-checkout__label__text">
<span><!-- ko text: $t('Personal number')--><!-- /ko --></span>
</label>
<div class="control">
<input type="text" class="input-text"
name="payment[ssn]"
data-bind="
attr: {
id: getCode() + '_ssn_' + value,
title: $t('Social Security Number'),
'data-container': getCode() + '-ssn',
maxlength : getSsnLength()
},
value: ssn"
data-validate="{required:true}"
/>
</div>
</div>
<!--/ko-->
<div class="checkout-component-dock" afterRender="renderKlarnaComponent()" data-bind="attr: { id: 'klarnaContainer'}"></div>
<!--/ko-->
<!-- ko if: isPaymentMethodAfterPay() -->
<!-- ko if: showSsn() -->
<div class="field ssn type required">
<label data-bind="attr: {for: getCode() + '_ssn_' + value}" class="adyen-checkout__label__text">
<span><!-- ko text: $t('Personal number')--><!-- /ko --></span>
</label>
<div class="control">
<input type="text" class="input-text"
name="payment[ssn]"
data-bind="
attr: {
id: getCode() + '_ssn_' + value,
title: $t('Social Security Number'),
'data-container': getCode() + '-ssn',
maxlength : getSsnLength()
},
value: ssn"
data-validate="{required:true}"
/>
</div>
</div>
<!--/ko-->
<div class="checkout-component-dock" afterRender="renderAfterPayComponent()" data-bind="attr: { id: 'afterPayContainer'}"></div>
<!--/ko-->
<!-- ko if: isPaymentMethodOtherOpenInvoiceMethod() -->
<div class="field gender required">
<label data-bind="attr: {for: getCode() + '_gender_type_' + value}" class="label">
<span><!-- ko text: $t('Gender')--><!-- /ko --></span>
</label>
<div class="control">
<select class="select select-gender-type"
name="payment[gender]"
data-bind="attr: {id: getCode() + '_gender_type_' + value, 'data-container': getCode() + '-gender-type'},
options: $parent.getGenderTypes(),
optionsValue: 'key',
optionsText: 'value',
optionsCaption: $t('-Please select-'),
value: gender"
data-validate="{required:true}">
</select>
</div>
</div>
<div class="field dob type required">
<label data-bind="attr: {for: getCode() + '_dob_' + value}" class="label">
<span><!-- ko text: $t('Date of Birth')--><!-- /ko --></span>
</label>
<div class="control">
<input type="text" class="input-text"
name="payment[dob]"
data-bind="
attr: {
id: getCode() + '_dob_' + value,
title: $t('Date of Birth'),
'data-container': getCode() + '-dob_' + value,
},
datepicker: {
storage: datepickerValue,
options: { showOn: 'both', changeYear: true, yearRange: '-99:-1', defaultDate: '-20y' }
},
value: dob"
data-validate="{required:true}"
/>
</div>
</div>
<div class="field telephone type required">
<label data-bind="attr: {for: getCode() + '_telephone_' + value}" class="label">
<span><!-- ko text: $t('Telephone')--><!-- /ko --></span>
</label>
<div class="control">
<input type="number" class="input-text"
name="payment[telephone]"
data-bind="
attr: {
id: getCode() + '_telephone_' + value,
title: $t('Telephone'),
'data-container': getCode() + '-telephone_' + value,
'data-validate': JSON.stringify({'required-number':true})
},
value: telephone"
data-validate="{required:true}"
/>
</div>
</div>
<!-- ko if: showSsn() -->
<div class="field ssn type required">
<label data-bind="attr: {for: getCode() + '_ssn_' + value}" class="adyen-checkout__label__text">
<span><!-- ko text: $t('Personal number')--><!-- /ko --></span>
</label>
<div class="control">
<input type="text" class="input-text"
name="payment[ssn]"
data-bind="
attr: {
id: getCode() + '_ssn_' + value,
title: $t('Social Security Number'),
'data-container': getCode() + '-ssn',
maxlength : getSsnLength()
},
value: ssn"
data-validate="{required:true}"
/>
</div>
</div>
<!--/ko-->
<!--/ko-->
<!-- ko if: isSepaDirectDebit() -->
<div class="checkout-component-dock" afterRender="renderSepaDirectDebitComponent()" data-bind="attr: { id: 'sepaDirectDebitContainer'}"></div>
<!--/ko-->
<!-- ko if: isAch() -->
<div class="field ownerName type required">
<label data-bind="attr: {for: getCode() + '_ownerName_' + value}" class="label">
<span><!-- ko text: $t('Owner name')--><!-- /ko --></span>
</label>
<div class="control">
<input type="text" class="input-text"
name="payment[ownerName]"
data-bind="
attr: {
id: getCode() + '_ownerName_' + value,
title: $t('Owner name'),
'data-container': getCode() + '-ownerName_' + value,
'data-validate': JSON.stringify({'required':true})
},
value: ownerName"
data-validate="{required:true}"
/>
</div>
</div>
<div class="field bankAccountNumber type required">
<label data-bind="attr: {for: getCode() + '_bankAccountNumber_' + value}" class="label">
<span><!-- ko text: $t('Bank account number')--><!-- /ko --></span>
</label>
<div class="control">
<input type="number" class="input-text"
name="payment[bankAccountNumber]"
data-bind="
attr: {
id: getCode() + '_bankAccountNumber_' + value,
title: $t('Bank account number'),
'data-container': getCode() + '-bankAccountNumber_' + value,
'data-validate': JSON.stringify({'required':true}),
minlength: 3,
maxlength : getBankAccountNumberMaxLength()
},
value: bankAccountNumber"
data-validate="{required:true}"
/>
</div>
</div>
<div class="field bankLocationId type required">
<label data-bind="attr: {for: getCode() + '_bankLocationId_' + value}" class="label">
<span><!-- ko text: $t('Bank location ID')--><!-- /ko --></span>
</label>
<div class="control">
<input type="number" class="input-text"
name="payment[bankLocationId]"
data-bind="
attr: {
id: getCode() + '_bankLocationId_' + value,
title: $t('Bank location ID'),
'data-container': getCode() + '-bankLocationId_' + value,
'data-validate': JSON.stringify({'required-number':true}),
minlength: 9,
maxlength: 9
},
value: bankLocationId"
data-validate="{required:true}"
/>
</div>
</div>
<!--/ko-->
</fieldset> </fieldset>
<div class="checkout-agreements-block"> <div class="checkout-agreements-block">
<!-- ko foreach: $parents[1].getRegion('before-place-order') --> <!-- ko foreach: $parents[1].getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko --> <!-- ko template: getTemplate() --><!-- /ko -->
...@@ -296,7 +65,7 @@ ...@@ -296,7 +65,7 @@
</div> </div>
<div> <div>
<span class="message message-error error hpp-message" data-bind="attr: {id: 'messages-' + value}"></span> <span class="message message-error error hpp-message" data-bind="attr: {id: 'messages-' + brandCode}"></span>
</div> </div>
<div class="actions-toolbar"> <div class="actions-toolbar">
...@@ -305,7 +74,7 @@ ...@@ -305,7 +74,7 @@
type="submit" type="submit"
data-bind=" data-bind="
click: $parent.continueToAdyenBrandCode, click: $parent.continueToAdyenBrandCode,
enable: placeOrderAllowed() && (value == $parent.isBrandCodeChecked()), enable: placeOrderAllowed() && (brandCode == $parent.isBrandCodeChecked()),
css: {disabled: !$parent.isPlaceOrderActionAllowed()}" css: {disabled: !$parent.isPlaceOrderActionAllowed()}"
disabled> disabled>
<span data-bind="text: $t('Place Order')"></span> <span data-bind="text: $t('Place Order')"></span>
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* Author: Adyen <magento@adyen.com> * Author: Adyen <magento@adyen.com>
*/ */
--> -->
<!-- ko foreach: getAdyenBillingAgreements() --> <!-- ko foreach: getAdyenStoredPayments() -->
<div class="payment-method" data-bind="css: {'_active': (value == $parent.isBillingAgreementChecked())}"> <div class="payment-method" data-bind="css: {'_active': (value == $parent.isBillingAgreementChecked())}">
<div class="payment-method-title field choice"> <div class="payment-method-title field choice">
<input type="radio" <input type="radio"
...@@ -46,7 +46,8 @@ ...@@ -46,7 +46,8 @@
<div class="payment-method-content"> <div class="payment-method-content">
<!-- ko ifnot: (getOriginKey()) --> <!-- ko ifnot: (getOriginKey()) -->
<span class="message message-error error"><!-- ko text: $t('Please configure an API Key and a live endpoint prefix(if in Production Mode) in your Adyen Required Settings')--><!-- /ko --></span> <span class="message message-error error"><!-- ko text: $t('Please configure an API Key and a live endpoint prefix(if in Production Mode) in your Adyen Required Settings')-->
<!-- /ko --></span>
<!--/ko--> <!--/ko-->
<!-- ko foreach: $parent.getRegion(getMessageName()) --> <!-- ko foreach: $parent.getRegion(getMessageName()) -->
...@@ -69,72 +70,12 @@ ...@@ -69,72 +70,12 @@
}, 'validation':[]}"> }, 'validation':[]}">
<fieldset <fieldset
data-bind="attr: {class: 'fieldset payment items ccard ' + getCode(), id: 'payment_form_' + $parent.getCode() + '_' + value}"> data-bind="attr: {class: 'fieldset payment items ccard ' + getCode(), id: 'payment_form_' + $parent.getCode() + '_' + value}">
<!-- ko if: agreement_data.card --> <div class="checkout-component-dock" afterRender="renderStoredPaymentComponent()"
<div class="field number"> data-bind="attr: { id: 'storedPaymentContainer-' + value}"></div>
<label class="label">
<span><!-- ko text: $t('Credit Card Number')--><!-- /ko --></span>
</label>
<div class="control">
<span data-bind="text: '**** **** **** ' + agreement_data.card.number"></span>
</div>
</div>
<div class="checkout-component-dock" afterRender="renderSecureCVC()" data-bind="attr: { id: 'cvcContainer-' + value}"></div>
<!--/ko-->
<!-- ko if: agreement_data.bank -->
<div class="field number">
<label class="label">
<span><!-- ko text: $t('Bank account holder name')--><!-- /ko --></span>
</label>
<div class="control">
<span data-bind="text: agreement_data.bank.ownerName"></span>
</div>
</div>
<div class="field number">
<label class="label">
<span><!-- ko text: $t('Iban')--><!-- /ko --></span>
</label>
<div class="control">
<span data-bind="text: agreement_data.bank.iban"></span>
</div>
</div>
<div class="field number">
<label class="label">
<span><!-- ko text: $t('Country')--><!-- /ko --></span>
</label>
<div class="control">
<span data-bind="text: agreement_data.bank.countryCode"></span>
</div>
</div>
<!--/ko--> <!--/ko-->
<!-- ko if: number_of_installments.length > 0 -->
<div class="field required"
data-bind="attr: {id: getCode() + '_installments_div'}, visible: getInstallments().length > 0">
<label data-bind="attr: {for: getCode() + '_installments'}" class="label">
<span><!-- ko text: $t('Installments')--><!-- /ko --></span>
</label>
<div class="control">
<select class="select"
name="payment[number_of_installments]"
data-bind="attr: {id: getCode() + '_installments', 'data-container': getCode() + '-installments', 'data-validate': JSON.stringify({required:false})},
enable: $parent.isActive($parents),
options: getInstallments,
optionsValue: 'value',
optionsText: 'key',
optionsCaption: $t('Do not use Installments'),
value: installment"
data-validate="{required:true}">
</select>
</div>
</div>
<!-- /ko -->
<div id="threeDS2ModalOneClick"> <div id="threeDS2ModalOneClick">
<div id="threeDS2ContainerOneClick"></div> <div id="threeDS2ContainerOneClick"></div>
</div> </div>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment