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

Commit 99397b67 authored by attilak's avatar attilak Committed by Rik ter Beek

- Modifications based on code review

- Card components instead of CSE
- 3D secure adjusted
- Installments adjusted

- Dependent php-api-library change (on the branch PW-306)
parent 687dc086
......@@ -51,9 +51,6 @@ class APIKeyMessage implements \Magento\Framework\Notification\MessageInterface
*/
protected $authSession;
/**
* Message identity
*/
const MESSAGE_IDENTITY = 'Adyen API Key Control message';
/**
......@@ -95,14 +92,20 @@ class APIKeyMessage implements \Magento\Framework\Notification\MessageInterface
public function isDisplayed()
{
// Only execute the query the first time you access the Admin page
if ($this->authSession->isFirstPageAfterLogin() && $this->_adyenHelper->getWsUsername()) {
if ($this->authSession->isFirstPageAfterLogin() && empty($this->_adyenHelper->getAPIKey())) {
try {
$title = "Adyen extension requires the API KEY!";
if (!empty($this->_adyenHelper->getWsUsername())) {
$description = "Please provide API-KEY for the webservice user " . $this->_adyenHelper->getWsUsername() . " for default/store " . $this->storeManagerInterface->getStore()->getName();
}else{
$description = "Please provide API-KEY for default/store " . $this->storeManagerInterface->getStore()->getName();
}
$messageData[] = array(
'severity' => $this->getSeverity(),
'date_added' => date("Y-m-d"),
'title' => $title,
'description' => "Please provide API-KEY for the webserver user " . $this->_adyenHelper->getWsUsername() . " for default/store " . $this->storeManagerInterface->getStore()->getName(),
'description' => $description,
'url' => "https://docs.adyen.com/developers/plug-ins-and-partners/magento-2/set-up-the-plugin-in-magento#step3configuretheplugininmagento",
);
......@@ -111,13 +114,8 @@ class APIKeyMessage implements \Magento\Framework\Notification\MessageInterface
* otherwise it will create it and add it to the inbox.
*/
$this->_inboxFactory->create()->parse(array_reverse($messageData));
/*
* Only show the message if the API Key is not set
*/
if (empty($this->_adyenHelper->getAPIKey())) {
return true;
}
} catch (\Exception $e) {
return false;
}
......
<?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\Gateway\Http\Client;
use Magento\Payment\Gateway\Http\ClientInterface;
/**
* Class TransactionSale
*/
class TransactionPayment implements ClientInterface
{
/**
* @var \Adyen\Client
*/
protected $client;
/**
* PaymentRequest constructor.
*
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Encryption\EncryptorInterface $encryptor
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Adyen\Payment\Model\RecurringType $recurringType
* @param array $data
*/
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Framework\Encryption\EncryptorInterface $encryptor,
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Adyen\Payment\Model\RecurringType $recurringType,
array $data = []
) {
$this->_encryptor = $encryptor;
$this->_adyenHelper = $adyenHelper;
$this->_adyenLogger = $adyenLogger;
$this->_recurringType = $recurringType;
$this->_appState = $context->getAppState();
$this->client = $this->_adyenHelper->initializeAdyenClient();
}
/**
* @param \Magento\Payment\Gateway\Http\TransferInterface $transferObject
* @return mixed
* @throws ClientException
*/
public function placeRequest(\Magento\Payment\Gateway\Http\TransferInterface $transferObject)
{
$request = $transferObject->getBody();
$service = new \Adyen\Service\Checkout($this->client);
try {
$response = $service->payments($request);
} catch(\Adyen\AdyenException $e) {
$response['error'] = $e->getMessage();
}
return $response;
}
}
......@@ -38,6 +38,11 @@ class CcAuthorizationDataBuilder implements BuilderInterface
*/
private $appState;
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
protected $_adyenLogger;
/**
* CcAuthorizationDataBuilder constructor.
*
......@@ -46,10 +51,13 @@ class CcAuthorizationDataBuilder implements BuilderInterface
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Model\Context $context
) {
\Magento\Framework\Model\Context $context,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger
)
{
$this->adyenHelper = $adyenHelper;
$this->appState = $context->getAppState();
$this->_adyenLogger = $adyenLogger;
}
/**
......@@ -65,13 +73,21 @@ class CcAuthorizationDataBuilder implements BuilderInterface
$storeId = $order->getStoreId();
$request = [];
$request['additionalData']['card.encrypted.json'] =
$payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_DATA);
$request['paymentMethod']['type'] = "scheme";
$request['paymentMethod']['encryptedCardNumber'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::CREDIT_CARD_NUMBER);
$request['paymentMethod']['encryptedExpiryMonth'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::EXPIRY_MONTH);
$request['paymentMethod']['encryptedExpiryYear'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::EXPIRY_YEAR);
$request['paymentMethod']['encryptedSecurityCode'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::SECURITY_CODE);
$request['paymentMethod']['holderName'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME);
// Remove from additional data
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_DATA);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::CREDIT_CARD_NUMBER);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::EXPIRY_MONTH);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::EXPIRY_YEAR);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::SECURITY_CODE);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_DATA);
/**
* if MOTO for backend is enabled use MOTO as shopper interaction type
......@@ -83,10 +99,10 @@ class CcAuthorizationDataBuilder implements BuilderInterface
$request['shopperInteraction'] = "Moto";
}
// if installments is set add it into the request
if ($payment->getAdditionalInformation('number_of_installments') &&
$payment->getAdditionalInformation('number_of_installments') > 0
if ($payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS) &&
$payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS) > 0
) {
$request['installments']['value'] = $payment->getAdditionalInformation('number_of_installments');
$request['installments']['value'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS);
}
return $request;
......
<?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\Gateway\Response;
use Magento\Payment\Gateway\Response\HandlerInterface;
class CheckoutPaymentCommentHistoryHandler implements HandlerInterface
{
/**
* @param array $handlingSubject
* @param array $response
* @return $this
*/
public function handle(array $handlingSubject, array $response)
{
$payment = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($handlingSubject);
/** @var OrderPaymentInterface $payment */
$payment = $payment->getPayment();
$commentText = "Adyen Result response:";
if (isset($response['resultCode'])) {
$responseCode = $response['resultCode'];
} else {
// try to get response from response key (used for modifications
if (isset($response['response'])) {
$responseCode = $response['response'];
} else {
$responseCode = "";
}
}
if (isset($response['pspReference'])) {
$pspReference = $response['pspReference'];
} else {
$pspReference = "";
}
if ($responseCode) {
$commentText .= '<br /> authResult: ' . $responseCode;
$payment->getOrder()->setAdyenResulturlEventCode($responseCode);
}
if ($pspReference) {
$commentText .= '<br /> authResult: ' . $pspReference;
}
$comment = __($commentText);
$payment->getOrder()->addStatusHistoryComment($comment);
return $this;
}
}
<?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\Gateway\Response;
use Magento\Payment\Gateway\Response\HandlerInterface;
class CheckoutPaymentsDetailsHandler implements HandlerInterface
{
/**
* @param array $handlingSubject
* @param array $response
*/
public function handle(array $handlingSubject, array $response)
{
$payment = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($handlingSubject);
/** @var OrderPaymentInterface $payment */
$payment = $payment->getPayment();
// set transaction not to processing by default wait for notification
$payment->setIsTransactionPending(true);
// no not send order confirmation mail
$payment->getOrder()->setCanSendNewEmailFlag(false);
if (!empty($response['pspReference'])) {
// set pspReference as transactionId
$payment->setCcTransId($response['pspReference']);
$payment->setLastTransId($response['pspReference']);
// set transaction
$payment->setTransactionId($response['pspReference']);
}
// do not close transaction so you can do a cancel() and void
$payment->setIsTransactionClosed(false);
$payment->setShouldCloseParentTransaction(false);
}
}
<?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\Gateway\Validator;
use Magento\Payment\Gateway\Validator\AbstractValidator;
class CheckoutResponseValidator extends AbstractValidator
{
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
private $adyenLogger;
/**
* GeneralResponseValidator constructor.
*
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
*/
public function __construct(
\Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger
) {
$this->adyenLogger = $adyenLogger;
parent::__construct($resultFactory);
}
/**
* @param array $validationSubject
* @return \Magento\Payment\Gateway\Validator\ResultInterface
*/
public function validate(array $validationSubject)
{
$response = \Magento\Payment\Gateway\Helper\SubjectReader::readResponse($validationSubject);
$paymentDataObjectInterface = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($validationSubject);
$payment = $paymentDataObjectInterface->getPayment();
$payment->setAdditionalInformation('3dActive', false);
$isValid = true;
$errorMessages = [];
// validate result
if ($response && isset($response['resultCode'])) {
switch ($response['resultCode']) {
case "Authorised":
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
break;
case "Received":
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
// set additionalData
if (isset($response['additionalData']) && is_array($response['additionalData'])) {
$additionalData = $response['additionalData'];
if (isset($additionalData['boletobancario.dueDate'])) {
$payment->setAdditionalInformation(
'dueDate',
$additionalData['boletobancario.dueDate']
);
}
if (isset($additionalData['boletobancario.expirationDate'])) {
$payment->setAdditionalInformation(
'expirationDate',
$additionalData['boletobancario.expirationDate']
);
}
if (isset($additionalData['boletobancario.url'])) {
$payment->setAdditionalInformation(
'url',
$additionalData['boletobancario.url']
);
}
}
break;
case "RedirectShopper":
$payment->setAdditionalInformation('3dActive', true);
$issuerUrl = $response['redirect']['url'];
$paReq = $response['redirect']['data']['PaReq'];
$md = $response['redirect']['data']['MD'];
if (!empty($paReq) && !empty($md) && !empty($issuerUrl)) {
$payment->setAdditionalInformation('issuerUrl', $issuerUrl);
$payment->setAdditionalInformation('paRequest', $paReq);
$payment->setAdditionalInformation('md', $md);
} else {
$isValid = false;
$errorMsg = __('3D secure is not valid.');
$this->adyenLogger->error($errorMsg);;
$errorMessages[] = $errorMsg;
}
break;
case "Refused":
$errorMsg = __('The payment is REFUSED.');
// this will result the specific error
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
break;
default:
$errorMsg = __('Error with payment method please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
break;
}
} else {
$errorMsg = __('Error with payment method please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
}
return $this->createResult($isValid, $errorMessages);
}
}
......@@ -33,8 +33,8 @@ class Data extends AbstractHelper
const MODULE_NAME = 'adyen-magento2';
const TEST = 'test';
const LIVE = 'live';
const SECURE_FIELDS_SDK_TEST = "https://checkoutshopper-test.adyen.com/checkoutshopper/assets/js/sdk/checkoutSecuredFields.1.3.0.min.js";
const SECURE_FIELDS_SDK_LIVE = "https://checkoutshopper-live.adyen.com/checkoutshopper/assets/js/sdk/checkoutSecuredFields.1.3.0.min.js";
const CHECKOUT_CONTEXT_URL_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/';
const CHECKOUT_CONTEXT_URL_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/';
/**
* @var \Magento\Framework\Encryption\EncryptorInterface
......@@ -97,14 +97,19 @@ class Data extends AbstractHelper
protected $adyenLogger;
/**
* @var \Magento\Framework\UrlInterface
* @var \Adyen\Service\ServiceFactory
*/
protected $urlInterface;
protected $adyenServiceFactory;
/**
* @var \Adyen\Service\ServiceFactory
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $adyenServiceFactory;
protected $storeManager;
/**
* @var \Magento\Framework\App\CacheInterface
*/
protected $cache;
/**
* Data constructor.
......@@ -122,8 +127,9 @@ class Data extends AbstractHelper
* @param \Magento\Tax\Model\Calculation $taxCalculation
* @param \Magento\Framework\App\ProductMetadataInterface $productMetadata
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Magento\Framework\UrlInterface $urlInterface
* @param \Adyen\Service\ServiceFactory $adyenServiceFactory
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Framework\App\CacheInterface $cache
*/
public function __construct(
\Magento\Framework\App\Helper\Context $context,
......@@ -139,8 +145,9 @@ class Data extends AbstractHelper
\Magento\Tax\Model\Calculation $taxCalculation,
\Magento\Framework\App\ProductMetadataInterface $productMetadata,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Magento\Framework\UrlInterface $urlInterface,
\Adyen\Service\ServiceFactory $adyenServiceFactory
\Adyen\Service\ServiceFactory $adyenServiceFactory,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\App\CacheInterface $cache
) {
parent::__construct($context);
......@@ -156,8 +163,9 @@ class Data extends AbstractHelper
$this->_taxCalculation = $taxCalculation;
$this->productMetadata = $productMetadata;
$this->adyenLogger = $adyenLogger;
$this->urlInterface = $urlInterface;
$this->adyenServiceFactory = $adyenServiceFactory;
$this->storeManager = $storeManager;
$this->cache = $cache;
}
/**
......@@ -1042,20 +1050,6 @@ class Data extends AbstractHelper
;
}
/**
* Retrieves secure field sdk url based on the demo mode
*
* @return string
*/
public function getSecureFieldsSdk()
{
if ($this->isDemoMode()) {
return self::SECURE_FIELDS_SDK_TEST;
} else {
return self::SECURE_FIELDS_SDK_LIVE;
}
}
/**
* @param $formFields
* @param $count
......@@ -1352,11 +1346,17 @@ class Data extends AbstractHelper
*/
public function getOriginKeyForBaseUrl()
{
$baseUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_WEB);
$parsed = parse_url($baseUrl);
$domain = $parsed['scheme'] . "://" . $parsed['host'];
if (!$originKey = $this->cache->load("Adyen_origin_key_for_" . $domain)) {
$originKey = "";
$baseUrl = $this->urlInterface->getBaseUrl();
if ($originKeys = $this->getOriginKeys($baseUrl)) {
$originKey = $originKeys[$baseUrl];
if ($originKeys = $this->getOriginKeys($domain)) {
$originKey = $originKeys[$domain];
$this->cache->save($originKey, "Adyen_origin_key_for_" . $domain, array(), 60 * 60 * 24);
}
}
return $originKey;
......@@ -1383,4 +1383,16 @@ class Data extends AbstractHelper
$respone = $service->originKeys($params);
return $respone['originKeys'];
}
/**
* @param int|null $storeId
* @return string
*/
public function getCheckoutContextUrl($storeId = null) {
if ($this->isDemoMode($storeId)) {
return self::CHECKOUT_CONTEXT_URL_TEST;
}
return self::CHECKOUT_CONTEXT_URL_LIVE;
}
}
......@@ -24,9 +24,6 @@
namespace Adyen\Payment\Model\Ui;
use Magento\Checkout\Model\ConfigProviderInterface;
use Magento\Payment\Helper\Data as PaymentHelper;
use Magento\Framework\View\Asset\Source as Source;
use \Magento\Payment\Gateway\Config\Config as Config;
class AdyenCcConfigProvider implements ConfigProviderInterface
{
......@@ -65,24 +62,30 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
*/
private $ccConfig;
/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
private $storeManager;
/**
* AdyenCcConfigProvider constructor.
*
* @param PaymentHelper $paymentHelper
* @param \Magento\Payment\Helper\Data $paymentHelper
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\App\RequestInterface $request
* @param \Magento\Framework\UrlInterface $urlBuilder
* @param Source $assetSource
* @param \Magento\Framework\View\Asset\Source $assetSource
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Payment\Model\CcConfig $ccConfig
* @param Config $config
*/
public function __construct(
PaymentHelper $paymentHelper,
\Magento\Payment\Helper\Data $paymentHelper,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\App\RequestInterface $request,
\Magento\Framework\UrlInterface $urlBuilder,
Source $assetSource,
\Magento\Framework\View\Asset\Source $assetSource,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Payment\Model\CcConfig $ccConfig
) {
$this->_paymentHelper = $paymentHelper;
......@@ -91,6 +94,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
$this->_urlBuilder = $urlBuilder;
$this->_assetSource = $assetSource;
$this->ccConfig = $ccConfig;
$this->storeManager = $storeManager;
}
/**
......@@ -117,6 +121,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
'payment' => [
'ccform' => [
'availableTypes' => [$methodCode => $this->getCcAvailableTypes($methodCode)],
'availableTypesByAlt' => [$methodCode => $this->getCcAvailableTypesByAlt($methodCode)],
'months' => [$methodCode => $this->getCcMonths()],
'years' => [$methodCode => $this->getCcYears()],
'hasVerification' => [$methodCode => $this->hasVerification($methodCode)],
......@@ -126,17 +131,22 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
]);
$recurringType = $this->_adyenHelper->getAdyenAbstractConfigData('recurring_type');
$canCreateBillingAgreement = false;
if ($recurringType == "ONECLICK" || $recurringType == "ONECLICK,RECURRING") {
$canCreateBillingAgreement = true;
}
$config['payment']['adyenCc']['methodCode'] = self::CODE;
$config['payment']['adyenCc']['locale'] = $this->_adyenHelper->getStoreLocale($this->storeManager->getStore()->getId());
$config['payment']['adyenCc']['generationTime'] = date("c");
$config['payment']['adyenCc']['canCreateBillingAgreement'] = $canCreateBillingAgreement;
$config['payment']['adyenCc']['icons'] = $this->getIcons();
$config['payment']['adyenCc']['originKey'] = $this->_adyenHelper->getOriginKeyForBaseUrl();
$config['payment']['adyenCc']['secureFieldsSource'] = $this->_adyenHelper->getSecureFieldsSdk();
$config['payment']['adyenCc']['checkoutUrl'] = $this->_adyenHelper->getCheckoutContextUrl($this->storeManager->getStore()->getId());
// has installments by default false
$config['payment']['adyenCc']['hasInstallments'] = false;
......@@ -178,6 +188,29 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
return $types;
}
/**
* Retrieve availables credit card type codes by alt code
*
* @param string $methodCode
* @return array
*/
protected function getCcAvailableTypesByAlt($methodCode)
{
$types = [];
$ccTypes = $this->_adyenHelper->getAdyenCcTypes();
$availableTypes = $this->_adyenHelper->getAdyenCcConfigData('cctypes');
if ($availableTypes) {
$availableTypes = explode(',', $availableTypes);
foreach (array_keys($ccTypes) as $code) {
if (in_array($code, $availableTypes)) {
$types[$ccTypes[$code]['code_alt']] = $code;
}
}
}
return $types;
}
/**
* Get icons for available payment methods
*
......
......@@ -138,7 +138,8 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
$canCreateBillingAgreement = true;
}
$config['payment'] ['adyenOneclick']['librarySource'] = $this->_adyenHelper->getLibrarySource();
// Commented out otherwise would break the checkoutsince the getLibrarySource is removed
//$config['payment'] ['adyenOneclick']['librarySource'] = $this->_adyenHelper->getLibrarySource();
$config['payment']['adyenOneclick']['generationTime'] = date("c");
$config['payment']['adyenOneclick']['canCreateBillingAgreement'] = $canCreateBillingAgreement;
......
......@@ -32,18 +32,28 @@ use Magento\Quote\Api\Data\PaymentInterface;
class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
{
const CC_TYPE = 'cc_type';
const ENCRYPTED_DATA = 'encrypted_data';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const STORE_CC = 'store_cc';
const CREDIT_CARD_NUMBER = 'number';
const SECURITY_CODE = 'cvc';
const EXPIRY_MONTH = 'expiryMonth';
const EXPIRY_YEAR = 'expiryYear';
const HOLDER_NAME = 'holderName';
const ENCRYPTED_DATA = 'encrypted_data';
/**
* @var array
*/
protected $additionalInformationList = [
self::CC_TYPE,
self::ENCRYPTED_DATA,
self::NUMBER_OF_INSTALLMENTS,
self::STORE_CC
self::STORE_CC,
self::CREDIT_CARD_NUMBER,
self::SECURITY_CODE,
self::EXPIRY_MONTH,
self::EXPIRY_YEAR,
self::HOLDER_NAME
];
/**
......
......@@ -426,8 +426,8 @@
<arguments>
<argument name="requestBuilder" xsi:type="object">AdyenPaymentCcAuthorizeRequest</argument>
<argument name="transferFactory" xsi:type="object">Adyen\Payment\Gateway\Http\TransferFactory</argument>
<argument name="client" xsi:type="object">Adyen\Payment\Gateway\Http\Client\TransactionAuthorization</argument>
<argument name="validator" xsi:type="object">GeneralResponseValidator</argument>
<argument name="client" xsi:type="object">Adyen\Payment\Gateway\Http\Client\TransactionPayment</argument>
<argument name="validator" xsi:type="object">CheckoutResponseValidator</argument>
<argument name="handler" xsi:type="object">AdyenPaymentCcResponseHandlerComposite</argument>
</arguments>
</virtualType>
......@@ -650,8 +650,8 @@
<virtualType name="AdyenPaymentCcResponseHandlerComposite" type="Magento\Payment\Gateway\Response\HandlerChain">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="payment_details" xsi:type="string">Adyen\Payment\Gateway\Response\PaymentAuthorisationDetailsHandler</item>
<item name="payment_comments" xsi:type="string">Adyen\Payment\Gateway\Response\PaymentCommentHistoryHandler</item>
<item name="payment_details" xsi:type="string">Adyen\Payment\Gateway\Response\CheckoutPaymentsDetailsHandler</item>
<item name="payment_comments" xsi:type="string">Adyen\Payment\Gateway\Response\CheckoutPaymentCommentHistoryHandler</item>
</argument>
</arguments>
</virtualType>
......@@ -841,6 +841,13 @@
</arguments>
</virtualType>
<!--Checkout Response validator-->
<virtualType name="CheckoutResponseValidator" type="Adyen\Payment\Gateway\Validator\CheckoutResponseValidator">
<arguments>
<argument name="loggerInterface" xsi:type="object">Adyen\Payment\Logger\AdyenLogger</argument>
</arguments>
</virtualType>
<virtualType name="PosCloudResponseValidator" type="Adyen\Payment\Gateway\Validator\PosCloudResponseValidator">
<arguments>
<argument name="loggerInterface" xsi:type="object">Adyen\Payment\Logger\AdyenLogger</argument>
......
......@@ -52,3 +52,4 @@
"You will be redirected to the Adyen App", "You will be redirected to the Adyen App"
"Continue to Adyen App", "Continue to Adyen App"
"Do not use Installments", "Do not use Installments"
"(Please provide a card with the type from the list above)", "(Please provide a card with the type from the list above)"
\ No newline at end of file
......@@ -52,3 +52,4 @@
"You will be redirected to the Adyen App", "U wordt doorgestuurd naar de Adyen-app"
"Continue to Adyen App", "Doorgaan naar Adyen-app"
"Do not use Installments", "Gebruik geen wederkerende betalingen"
"(Please provide a card with the type from the list above)", "(Please provide a card with the type from the list above)"
......@@ -25,8 +25,6 @@
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
<head>
<css src="Adyen_Payment::css/styles.css"/>
<script src="Adyen_Payment::js/adyen.2.0.0.js"></script>
<script src="Adyen_Payment::js/adyen.checkout.js"></script>
</head>
<body>
<referenceBlock name="checkout.root">
......
......@@ -20,10 +20,35 @@
* Author: Adyen <magento@adyen.com>
*/
.hidden {
display: none;
}
.checkout-payment-method .ccard .changable-card-expiry { display:none; }
.checkout-payment-method .ccard .changable-card-expiry._active { display:block; }
.checkout-payment-method .ccard .expire-update._disable { display:none; }
.checkout-payment-method .ccard .holdername .input-text { width: 225px; }
.checkout-payment-method .ccard .holdername .input-text {
width: 225px;
border: none;
padding: 0;
color: rgb(0, 27, 43);
font-size: 16px;
font-weight: 400;
}
.checkout-payment-method .ccard .holdername .input-text:focus {
border: none;
box-shadow: none;
}
.checkout-payment-method .ccard .holdername .input-text::placeholder,
.checkout-payment-method .ccard .holdername .input-text:placeholder-shown
{
color: rgb(144, 162, 189);
font-weight: 200;
}
.checkout-payment-method .payment-method-title, .checkout-payment-method .payment-method-title label {
display: -webkit-flex;
......@@ -139,6 +164,22 @@
min-height: 42px; /* override magento min-height */
}
/* Checkout card components style */
.adyen-checkout-card__form .adyen-checkout__input iframe{
max-height: 40px;
}
.adyen-checkout-card__form .adyen-checkout__input img{
display: none;
}
#adyen-cc-form .fieldset > .field > .label, .fieldset > .fields > .field > .label {
font-weight: 400;
}
#adyen-cc-form .helper-text{
font-size: 11px;
color: rgb(144, 162, 189);
font-weight: 100;
}
\ No newline at end of file
......@@ -29,73 +29,80 @@ define(
'Magento_Checkout/js/model/payment/additional-validators',
'Magento_Checkout/js/model/quote',
'Adyen_Payment/js/model/installments',
'mage/url'
'mage/url',
'Adyen_Payment/js/adyen.2.0.0',
'Adyen_Payment/js/adyen.checkout'
],
function ($, ko, Component, customer, creditCardData, additionalValidators, quote, installments, url) {
'use strict';
var cvcLength = ko.observable(4);
return Component.extend({
defaults: {
template: 'Adyen_Payment/payment/cc-form',
creditCardOwner: '',
encryptedData: '',
setStoreCc: true,
installment: ''
installment: '',
creditCardDetailsValid: false
},
initObservable: function () {
this._super()
.observe([
'creditCardType',
'creditCardExpYear',
'creditCardExpMonth',
'creditCardNumber',
'creditCardVerificationNumber',
'creditCardSsStartMonth',
'creditCardSsStartYear',
'selectedCardType',
'creditCardOwner',
'encryptedData',
'generationtime',
'creditCardNumber',
'securityCode',
'expiryMonth',
'expiryYear',
'setStoreCc',
'installment'
'installment',
'creditCardDetailsValid'
]);
return this;
},
getInstallments: installments.getInstallments(),
initialize: function () {
/**
* Renders the secure fields,
* creates the card component,
* sets up the callbacks for card components and
* set up the installments
*/
renderSecureFields: function() {
var self = this;
this._super();
installments.setInstallments(0);
// include secure fields sdk javascript
var secureFieldsScriptTag = document.createElement('script');
secureFieldsScriptTag.id = "secure-fields-script-tag";
secureFieldsScriptTag.src = this.getSecureFieldsSource();
secureFieldsScriptTag.type = "text/javascript";
document.body.appendChild(secureFieldsScriptTag)
self.creditCardOwner.subscribe(function () {
self.updateButton();
});
//Set credit card number to credit card data object
this.creditCardNumber.subscribe(function (value) {
installments.setInstallments(0);
// installments enabled ??
var allInstallments = self.getAllInstallments();
var cardNode = document.getElementById('cardContainer');
// what card is this ??
var checkout = new Adyen.Checkout({
locale: window.checkoutConfig.payment.adyenCc.locale
});
if (creditCardData.creditCard) {
var creditcardType = creditCardData.creditCard.type;
var card = checkout.create('card', {
originKey: window.checkoutConfig.payment.adyenCc.originKey,
loadingContext: window.checkoutConfig.payment.adyenCc.checkoutUrl,
type: 'card',
groupTypes: self.getAvailableCardTypeAltCodes(),
cvcLength(4);
if (creditcardType != "AE") {
cvcLength(3);
}
if (creditcardType in allInstallments) {
onChange: function(state) {
// what card is this ??
// 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) {
if (creditCardType in allInstallments) {
// get for the creditcard the installments
var installmentCreditcard = allInstallments[creditcardType];
var installmentCreditcard = allInstallments[creditCardType];
var grandTotal = quote.totals().grand_total;
var numberOfInstallments = [];
......@@ -123,39 +130,54 @@ define(
installments.setInstallments(0);
}
}
});
},
setPlaceOrderHandler: function (handler) {
this.placeOrderHandler = handler;
},
setValidateHandler: function (handler) {
this.validateHandler = handler;
},
getCode: function () {
return 'adyen_cc';
// Color the image of the credit card
self.creditCardType(creditCardType);
}else{
self.creditCardType("")
}
if (state.isValid) {
// Here we enable the button if the component is now valid
self.creditCardNumber(state.data.encryptedCardNumber);
self.expiryMonth(state.data.encryptedExpiryMonth);
self.expiryYear(state.data.encryptedExpiryYear);
self.securityCode(state.data.encryptedSecurityCode);
self.creditCardDetailsValid(true);
}else{
self.creditCardDetailsValid(false);
}
self.updateButton();
},
getOriginKey: function () {
return window.checkoutConfig.payment.adyenCc.originKey;
onError: function() {}
});
card.mount(cardNode);
self.isPlaceOrderActionAllowed(false);
},
/**
* Builds the payment details part of the payment information reqeust
*
* @returns {{method: *, additional_data: {cc_type: *, number: *, cvc, expiryMonth: *, expiryYear: *, holderName: *, generationtime: *, store_cc: *, number_of_installments: *}}}
*/
getData: function () {
return {
'method': this.item.method,
additional_data: {
'cc_type': this.creditCardType(),
'encrypted_data': this.encryptedData(),
'generationtime': this.generationtime(),
'number': this.creditCardNumber(),
'cvc': this.securityCode(),
'expiryMonth': this.expiryMonth(),
'expiryYear': this.expiryYear(),
'holderName': this.creditCardOwner(),
'generationtime': this.getGenerationTime(),
'store_cc': this.setStoreCc(),
'number_of_installments': this.installment()
}
};
},
getCvcLength: function () {
return cvcLength();
},
isActive: function () {
return true;
},
/**
* Returns state of place order button
* @returns {boolean}
......@@ -163,9 +185,26 @@ define(
isButtonActive: function() {
return this.isActive() && this.getCode() == this.isChecked() && this.isPlaceOrderActionAllowed();
},
/**
* Checks if the pay button can be enabled and enables if can
*/
updateButton: function() {
var self = this;
if (self.isCardOwnerValid() && self.isCreditCardDetailsValid()) {
self.isPlaceOrderActionAllowed(true);
} else {
self.isPlaceOrderActionAllowed(false);
}
},
/**
* Custom place order function
*
* @override
*
* @param data
* @param event
* @returns {boolean}
*/
placeOrder: function (data, event) {
var self = this;
......@@ -174,22 +213,6 @@ define(
event.preventDefault();
}
var options = {};
var cseInstance = adyen.createEncryption(options);
var generationtime = this.getGenerationTime();
var cardData = {
number: this.creditCardNumber(),
cvc: this.creditCardVerificationNumber(),
expiryMonth: this.creditCardExpMonth(),
expiryYear: this.creditCardExpYear(),
holderName: this.creditCardOwner(),
generationtime: generationtime
};
var data = cseInstance.encrypt(cardData);
this.encryptedData(data);
if (this.validate() && additionalValidators.validate()) {
this.isPlaceOrderActionAllowed(false);
......@@ -214,24 +237,88 @@ define(
return false;
},
getControllerName: function () {
return window.checkoutConfig.payment.iframe.controllerName[this.getCode()];
/**
* Validates the payment date when clicking the pay button
*
* @returns {boolean}
*/
validate: function () {
var self = this;
var form = 'form[data-role=adyen-cc-form]';
var validate = $(form).validation() && $(form).validation('isValid');
var owner = Boolean($(form + ' #creditCardHolderName').valid());
if (!validate || !owner) {
return false;
}
return true;
},
getPlaceOrderUrl: function () {
return window.checkoutConfig.payment.iframe.placeOrderUrl[this.getCode()];
/**
* 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;
},
context: function () {
return this;
/**
* 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
*
* @param altCode
* @returns {*}
*/
getCcCodeByAltCode: function(altCode) {
var ccTypes = window.checkoutConfig.payment.ccform.availableTypesByAlt[this.getCode()];
if (ccTypes.hasOwnProperty(altCode)) {
return ccTypes[altCode];
}
isCseEnabled: function () {
return window.checkoutConfig.payment.adyenCc.cseEnabled;
return "";
},
getCSEKey: function () {
return window.checkoutConfig.payment.adyenCc.cseKey;
/**
* Get available card types translated to the Adyen card type codes
* (The card type alt code is the Adyen card type code)
*
* @returns {string[]}
*/
getAvailableCardTypeAltCodes: function() {
var ccTypes = window.checkoutConfig.payment.ccform.availableTypesByAlt[this.getCode()];
return Object.keys(ccTypes);
},
getSecureFieldsSource: function () {
return window.checkoutConfig.payment.adyenCc.secureFieldsSource;
/**
* Return Payment method code
*
* @returns {*}
*/
getCode: function () {
return window.checkoutConfig.payment.adyenCc.methodCode;
},
isActive: function () {
return true;
},
getControllerName: function () {
return window.checkoutConfig.payment.iframe.controllerName[this.getCode()];
},
getPlaceOrderUrl: function () {
return window.checkoutConfig.payment.iframe.placeOrderUrl[this.getCode()];
},
getGenerationTime: function () {
return window.checkoutConfig.payment.adyenCc.generationTime;
......@@ -240,30 +327,12 @@ define(
if (customer.isLoggedIn()) {
return window.checkoutConfig.payment.adyenCc.canCreateBillingAgreement;
}
return false;
},
isShowLegend: function () {
return true;
},
validate: function () {
var form = 'form[data-role=adyen-cc-form]';
var validate = $(form).validation() && $(form).validation('isValid');
// add extra validation because jquery validation will not work on non name attributes
var ccNumber = Boolean($(form + ' #creditCardNumber').valid());
var owner = Boolean($(form + ' #creditCardHolderName').valid());
var expiration = Boolean($(form + ' #adyen_cc_expiration').valid());
var expiration_yr = Boolean($(form + ' #adyen_cc_expiration_yr').valid());
var cid = Boolean($(form + ' #adyen_cc_cc_cid').valid());
if (!validate || !ccNumber || !owner || !expiration || !expiration_yr || !cid) {
return false;
}
return true;
},
showLogo: function () {
return window.checkoutConfig.payment.adyen.showLogo;
},
......@@ -277,9 +346,16 @@ define(
},
getAllInstallments: function () {
return window.checkoutConfig.payment.adyenCc.installments;
},
setPlaceOrderHandler: function (handler) {
this.placeOrderHandler = handler;
},
setValidateHandler: function (handler) {
this.validateHandler = handler;
},
context: function () {
return this;
}
});
}
);
......@@ -68,14 +68,37 @@
<br/>
<!-- /ko -->
<div class="field type required">
<div class="field holdername type">
<label data-bind="attr: {for: 'creditCardHolderName'}" class="label">
<span><!-- ko text: $t('Credit Card Owner')--><!-- /ko --></span>
</label>
<div class="control">
<input type="text"
class="input-text required-entry"
data-encrypted-name="holderName"
value=""
data-bind="attr: {
id: 'creditCardHolderName',
title: $t('Credit Card Owner'),
placeholder: $t('Credit Card Owner'),
'data-container': getCode() + '-cc-owner'
},
enable: isActive($parents),
value: creditCardOwner,
valueUpdate: 'keyup' "
data-validate="{required:true}"
/>
</div>
</div>
<div class="field type">
<label data-bind="attr: {for: getCode() + '_cc_type'}" class="label">
<span><!-- ko text: $t('Credit Card Type')--><!-- /ko --></span>
</label>
<div class="control">
<ul class="credit-card-types">
<!-- ko foreach: {data: getCcAvailableTypesValues(), as: 'item'} -->
<li class="item" data-bind="css: {_active: $parent.selectedCardType() == item.value} ">
<li class="item" data-bind="css: {_active: $parent.creditCardType() == item.value} ">
<!--ko if: $parent.getIcons(item.value) -->
<img data-bind="attr: {
'src': $parent.getIcons(item.value).url,
......@@ -87,6 +110,7 @@
</li>
<!--/ko-->
</ul>
<p class="helper-text" data-bind="css: {hidden: creditCardType() !== ''} "><!-- ko text: $t('(Please provide a card with the type from the list above)')--><!-- /ko --></p>
<input type="hidden"
name="payment[cc_type]"
class="input-text"
......@@ -96,121 +120,11 @@
">
</div>
</div>
<div class="field number required">
<label data-bind="attr: {for: 'creditCardNumber'}" class="label">
<span><!-- ko text: $t('Credit Card Number')--><!-- /ko --></span>
</label>
<div class="control">
<input type="tel" class="input-text" value=""
data-encrypted-name="number"
data-bind="attr: {
autocomplete: off,
id: 'creditCardNumber',
title: $t('Credit Card Number'),
'data-container': getCode() + '-cc-number',
'data-validate': JSON.stringify({'required-number':true, 'validate-card-type':getCcAvailableTypesValues(), 'validate-card-number':'#' + getCode() + '_cc_type', 'validate-cc-type':'#' + getCode() + '_cc_type'})},
enable: isActive($parents),
value: creditCardNumber,
valueUpdate: 'keyup' "/>
</div>
<div class="field number cardContainerField">
<div afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}" ></div>
</div>
<div class="field holdername type required">
<label data-bind="attr: {for: 'creditCardHolderName'}" class="label">
<span><!-- ko text: $t('Credit Card Owner')--><!-- /ko --></span>
</label>
<div class="control">
<input type="text"
class="input-text required-entry"
data-encrypted-name="holderName"
value=""
data-bind="attr: {
id: 'creditCardHolderName',
title: $t('Credit Card Owner'),
'data-container': getCode() + '-cc-owner'
},
enable: isActive($parents),
value: creditCardOwner,
valueUpdate: 'keyup' "
data-validate="{required:true}"
/>
</div>
</div>
<div class="field date required" data-bind="attr: {id: getCode() + '_cc_type_exp_div'}">
<label data-bind="attr: {for: 'cardExpirationMonth'}" class="label">
<span><!-- ko text: $t('Expiration Date')--><!-- /ko --></span>
</label>
<div class="control">
<div class="fields group group-2">
<div class="field no-label month">
<div class="control">
<select class="select select-month"
data-encrypted-name="expiryMonth"
data-bind="attr: {id: getCode() + '_expiration', 'data-container': getCode() + '-cc-month', 'data-validate': JSON.stringify({required:true, 'validate-cc-exp':'#' + getCode() + '_expiration_yr'})},
enable: isActive($parents),
options: getCcMonthsValues(),
optionsValue: 'value',
optionsText: 'month',
optionsCaption: $t('Month'),
value: creditCardExpMonth"
data-validate="{required:true}">
</select>
</div>
</div>
<div class="field no-label year">
<div class="control">
<select class="select select-year"
data-encrypted-name="expiryYear"
data-bind="attr: {id: getCode() + '_expiration_yr', 'data-container': getCode() + '-cc-year', 'data-validate': JSON.stringify({required:true})},
enable: isActive($parents),
options: getCcYearsValues(),
optionsValue: 'value',
optionsText: 'year',
optionsCaption: $t('Year'),
value: creditCardExpYear"
data-validate="{required:true}">
</select>
</div>
</div>
</div>
</div>
</div>
<!-- ko if: (hasVerification())-->
<div class="field cvv required" data-bind="attr: {id: getCode() + '_cc_type_cvv_div'}">
<label data-bind="attr: {for: getCode() + '_cc_cid'}" class="label">
<span><!-- ko text: $t('Card Verification Number')--><!-- /ko --></span>
</label>
<div class="control _with-tooltip">
<input type="number"
autocomplete="off"
class="input-text cvv"
data-encrypted-name="cvc"
value=""
data-bind="attr: {
id: getCode() + '_cc_cid',
title: $t('Card Verification Number'),
'data-container': getCode() + '-cc-cvv',
'data-validate': JSON.stringify({'required-number':true, 'validate-card-cvv':'#' + getCode() + '_cc_type'}),
maxLength : getCvcLength(),
oninput:'javascript: if (this.value.length > this.maxLength) this.value = this.value.slice(0, this.maxLength);'
},
enable: isActive($parents),
value: creditCardVerificationNumber" ,
data-validate="{required:true}"
/>
<div class="field-tooltip toggle">
<span class="field-tooltip-action action-cvv"
tabindex="0"
data-toggle="dropdown"
data-bind="attr: {title: $t('What is this?')}, mageInit: {'dropdown':{'activeClass': '_active'}}">
<span><!-- ko text: $t('What is this?')--><!-- /ko --></span>
</span>
<div class="field-tooltip-content"
data-target="dropdown"
data-bind="html: getCvvImageHtml()"></div>
</div>
</div>
</div>
<!-- /ko -->
<!-- ko if: (hasInstallments())-->
......
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