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 48b45ef5 authored by Rik ter Beek's avatar Rik ter Beek Committed by GitHub

Merge pull request #367 from Adyen/PW-790(incomplete)

Pw 790 Save and update billing agreements based on the response from the payments call
parents fa758982 37705217
......@@ -26,114 +26,123 @@ namespace Adyen\Payment\AdminMessage;
class APIKeyMessage implements \Magento\Framework\Notification\MessageInterface
{
/**
* @var \Adyen\Payment\Helper\Data
*/
protected $_adyenHelper;
/**
* @var \Magento\AdminNotification\Model\InboxFactory
*/
protected $_inboxFactory;
/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManagerInterface;
/**
* @var \Magento\Backend\Model\Auth\Session
*/
protected $authSession;
const MESSAGE_IDENTITY = 'Adyen API Key Control message';
/**
* APIKeyMessage constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\AdminNotification\Model\InboxFactory $inboxFactory
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\AdminNotification\Model\InboxFactory $inboxFactory,
\Magento\Store\Model\StoreManagerInterface $storeManagerInterface,
\Magento\Backend\Model\Auth\Session $authSession
) {
$this->_adyenHelper = $adyenHelper;
$this->_inboxFactory = $inboxFactory;
$this->storeManagerInterface = $storeManagerInterface;
$this->authSession = $authSession;
}
/**
* Retrieve unique system message identity
*
* @return string
*/
public function getIdentity()
{
return self::MESSAGE_IDENTITY;
}
/**
* Check whether the system message should be shown
*
* @return bool
*/
public function isDisplayed()
{
// Only execute the query the first time you access the Admin page
if ($this->authSession->isFirstPageAfterLogin() && empty($this->_adyenHelper->getAPIKey())) {
try {
$title = "Adyen extension requires the API KEY!";
$messageData[] = array(
'severity' => $this->getSeverity(),
'date_added' => date("Y-m-d"),
'title' => $title,
'description' => $this->getText(),
'url' => "https://docs.adyen.com/developers/plug-ins-and-partners/magento-2/set-up-the-plugin-in-magento#step3configuretheplugininmagento",
);
/*
* The parse function checks if the $versionData message exists in the inbox,
* otherwise it will create it and add it to the inbox.
*/
$this->_inboxFactory->create()->parse(array_reverse($messageData));
return true;
} catch (\Exception $e) {
return false;
}
}
return false;
}
/**
* Retrieve system message text
*
* @return \Magento\Framework\Phrase
*/
public function getText()
{
if (!empty($this->_adyenHelper->getWsUsername())) {
$message = "Please provide API-KEY for the webservice user " . $this->_adyenHelper->getWsUsername() . " for default/store " . $this->storeManagerInterface->getStore()->getName();
}else{
$message = "Please provide API-KEY for default/store " . $this->storeManagerInterface->getStore()->getName();
}
return $message;
}
/**
* Retrieve system message severity
*
* @return int
*/
public function getSeverity()
{
return self::SEVERITY_CRITICAL;
}
/**
* @var \Adyen\Payment\Helper\Data
*/
protected $adyenHelper;
/**
* @var \Magento\AdminNotification\Model\InboxFactory
*/
protected $inboxFactory;
/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManagerInterface;
/**
* @var \Magento\Backend\Model\Auth\Session
*/
protected $authSession;
const MESSAGE_IDENTITY = 'Adyen API Key Control message';
/**
* APIKeyMessage constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\AdminNotification\Model\InboxFactory $inboxFactory
* @param \Magento\Store\Model\StoreManagerInterface $storeManagerInterface
* @param \Magento\Backend\Model\Auth\Session $authSession
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\AdminNotification\Model\InboxFactory $inboxFactory,
\Magento\Store\Model\StoreManagerInterface $storeManagerInterface,
\Magento\Backend\Model\Auth\Session $authSession
) {
$this->adyenHelper = $adyenHelper;
$this->inboxFactory = $inboxFactory;
$this->storeManagerInterface = $storeManagerInterface;
$this->authSession = $authSession;
}
/**
* Retrieve unique system message identity
*
* @return string
*/
public function getIdentity()
{
return self::MESSAGE_IDENTITY;
}
/**
* Check whether the system message should be shown
*
* @return bool
*/
public function isDisplayed()
{
// Only execute the query the first time you access the Admin page
if ($this->authSession->isFirstPageAfterLogin() &&
!empty($this->adyenHelper->getWsUsername()) &&
empty($this->adyenHelper->getAPIKey())
) {
try {
$title = 'Adyen extension requires the API KEY!';
$messageData[] = [
'severity' => $this->getSeverity(),
'date_added' => date('Y-m-d'),
'title' => $title,
'description' => $this->getText(),
'url' => 'https://docs.adyen.com/developers/plug-ins-and-partners/magento-2/' .
'set-up-the-plugin-in-magento#step3configuretheplugininmagento',
];
/*
* The parse function checks if the $versionData message exists in the inbox,
* otherwise it will create it and add it to the inbox.
*/
$this->inboxFactory->create()->parse($messageData);
return true;
} catch (\Exception $e) {
return false;
}
}
return false;
}
/**
* Retrieve system message text
*
* @return string
* @throws \Magento\Framework\Exception\NoSuchEntityException
*/
public function getText()
{
$message = '';
if (!empty($this->adyenHelper->getWsUsername())) {
$message = 'Please provide API-KEY for the webservice user ' .
$this->adyenHelper->getWsUsername() . ' for default/store ' .
$this->storeManagerInterface->getStore()->getName();
}
return $message;
}
/**
* Retrieve system message severity
*
* @return int
*/
public function getSeverity()
{
return self::SEVERITY_CRITICAL;
}
}
......@@ -235,9 +235,7 @@ class Redirect extends \Magento\Payment\Block\Form
);
$formFields['shopperEmail'] = $shopperEmail;
// recurring
$recurringType = trim($this->_adyenHelper->getAdyenAbstractConfigData(
'recurring_type'
));
$recurringType = $this->_adyenHelper->getRecurringTypeFromOneclickRecurringSetting();
$brandCode = $this->_order->getPayment()->getAdditionalInformation(
\Adyen\Payment\Observer\AdyenHppDataAssignObserver::BRAND_CODE
);
......
......@@ -183,7 +183,7 @@ class PayByMailCommand implements CommandInterface
$formFields['shopperEmail'] = $shopperEmail;
// recurring
$recurringType = trim($this->_adyenHelper->getAdyenAbstractConfigData('recurring_type', $storeId));
$recurringType = $this->_adyenHelper->getRecurringTypeFromOneclickRecurringSetting($storeId);
$sessionValidity = $this->_adyenHelper->getAdyenPayByMailConfigData('session_validity', $storeId);
......
......@@ -65,7 +65,11 @@ class CcAuthorizationDataBuilder implements BuilderInterface
$storeId = $order->getStoreId();
$request = [];
// If ccType is set use this. For bcmc you need bcmc otherwise it will fail
$request['paymentMethod']['type'] = "scheme";
if ($payment->getAdditionalInformation(AdyenCcDataAssignObserver::VARIANT)) {
$request['paymentMethod']['type'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::VARIANT);
}
if ($cardNumber = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::CREDIT_CARD_NUMBER)) {
$request['paymentMethod']['encryptedCardNumber'] = $cardNumber;
......
......@@ -20,6 +20,7 @@
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
......@@ -50,9 +51,11 @@ class RecurringDataBuilder implements BuilderInterface
$this->appState = $context->getAppState();
}
/**
* @param array $buildSubject
* @return array
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function build(array $buildSubject)
{
......@@ -61,45 +64,25 @@ class RecurringDataBuilder implements BuilderInterface
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
// Needs to change when oneclick,cc using facade impl.
$paymentMethodCode = $payment->getMethodInstance()->getCode();
$customerId = $payment->getOrder()->getCustomerId();
$storeId = null;
if ($this->appState->getAreaCode() === \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE) {
$storeId = $payment->getOrder()->getStoreId();
}
$recurringType = $this->adyenHelper->getAdyenAbstractConfigData('recurring_type', $storeId);
// set the recurring type
$recurringContractType = null;
if ($recurringType) {
if ($paymentMethodCode == \Adyen\Payment\Model\Ui\AdyenOneclickConfigProvider::CODE) {
/*
* For ONECLICK look at the recurringPaymentType that the merchant
* has selected in Adyen ONECLICK settings
*/
if ($payment->getAdditionalInformation('customer_interaction')) {
$recurringContractType = \Adyen\Payment\Model\RecurringType::ONECLICK;
} else {
$recurringContractType = \Adyen\Payment\Model\RecurringType::RECURRING;
}
} elseif ($paymentMethodCode == \Adyen\Payment\Model\Ui\AdyenCcConfigProvider::CODE) {
if ($payment->getAdditionalInformation("store_cc") == "" &&
($recurringType == "ONECLICK,RECURRING" || $recurringType == "RECURRING")) {
$recurringContractType = \Adyen\Payment\Model\RecurringType::RECURRING;
} elseif ($payment->getAdditionalInformation("store_cc") == "1") {
$recurringContractType = $recurringType;
}
} else {
$recurringContractType = $recurringType;
}
$enableOneclick = $this->adyenHelper->getAdyenAbstractConfigData('enable_oneclick', $storeId);
$enableRecurring = $this->adyenHelper->getAdyenAbstractConfigData('enable_recurring', $storeId);
if ($enableOneclick) {
$result['enableOneclick'] = true;
}
if ($enableRecurring) {
$result['enableRecurring'] = true;
}
// only when recurringContractType is set and when a customer is loggedIn
if ($recurringContractType && $customerId > 0) {
$recurring = ['contract' => $recurringContractType];
$result['recurring'] = $recurring;
if ($payment->getAdditionalInformation('store_cc') === '1') {
$result['paymentMethod']['storeDetails'] = true;
}
return $result;
......
......@@ -27,35 +27,54 @@ 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();
/**
* @var \Adyen\Payment\Helper\Data
*/
protected $adyenHelper;
// set transaction not to processing by default wait for notification
$payment->setIsTransactionPending(true);
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper
) {
$this->adyenHelper = $adyenHelper;
}
// no not send order confirmation mail
$payment->getOrder()->setCanSendNewEmailFlag(false);
/**
* @param array $handlingSubject
* @param array $response
*/
public function handle(array $handlingSubject, array $response)
{
$payment = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($handlingSubject);
if (!empty($response['pspReference'])) {
// set pspReference as transactionId
$payment->setCcTransId($response['pspReference']);
$payment->setLastTransId($response['pspReference']);
/** @var OrderPaymentInterface $payment */
$payment = $payment->getPayment();
// set transaction
$payment->setTransactionId($response['pspReference']);
}
// set transaction not to processing by default wait for notification
$payment->setIsTransactionPending(true);
// do not close transaction so you can do a cancel() and void
$payment->setIsTransactionClosed(false);
$payment->setShouldCloseParentTransaction(false);
// 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']);
}
if (!empty($response['additionalData']) &&
!empty($response['additionalData']['recurring.recurringDetailReference'])
) {
$order = $payment->getOrder();
$this->adyenHelper->createAdyenBillingAgreement($order, $response['additionalData']);
}
// do not close transaction so you can do a cancel() and void
$payment->setIsTransactionClosed(false);
$payment->setShouldCloseParentTransaction(false);
}
}
This diff is collapsed.
......@@ -119,6 +119,8 @@ class PaymentRequest extends DataObject
throw new \Magento\Framework\Exception\LocalizedException(__('3D secure failed'));
}
$this->_adyenHelper->createAdyenBillingAgreement($order, $result['additionalData']);
return $result;
}
......
......@@ -29,7 +29,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
/**
* @var \Adyen\Payment\Helper\Data
*/
private $_adyenHelper;
private $adyenHelper;
/**
* Agreement constructor.
......@@ -66,7 +66,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
$data
);
$this->_adyenHelper = $adyenHelper;
$this->adyenHelper = $adyenHelper;
}
/**
......@@ -90,7 +90,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
->setReferenceId($data['recurringDetailReference'])
->setCreatedAt($data['creationDate']);
$creationDate = str_replace(' ', '-', $data['creationDate']);
$creationDate = str_replace(' ', '-', $data['creationDate']);
$this->setCreatedAt($creationDate);
//Billing agreement SEPA
......@@ -105,7 +105,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
// Billing agreement is CC
if (isset($data['card']['number'])) {
$ccType = $data['variant'];
$ccTypes = $this->_adyenHelper->getCcTypesAltData();
$ccTypes = $this->adyenHelper->getCcTypesAltData();
if (isset($ccTypes[$ccType])) {
$ccType = $ccTypes[$ccType]['name'];
......@@ -123,7 +123,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
}
if ($data['variant'] == 'paypal') {
$email = "";
$email = '';
if (isset($data['tokenDetails']['tokenData']['EmailId'])) {
$email = $data['tokenDetails']['tokenData']['EmailId'];
......@@ -150,9 +150,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
public function setAgreementData($data)
{
if (is_array($data)) {
unset($data['creationDate']);
unset($data['recurringDetailReference']);
unset($data['payment_method']);
unset($data['creationDate'], $data['recurringDetailReference'], $data['payment_method']);
}
$this->setData('agreement_data', json_encode($data));
......@@ -166,4 +164,51 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
{
return json_decode($this->getData('agreement_data'), true);
}
public function setCcBillingAgreement($contractDetail)
{
$this
->setMethodCode('adyen_oneclick')
->setReferenceId($contractDetail['recurring.recurringDetailReference']);
// Billing agreement is CC
if (isset($contractDetail['cardBin']) &&
isset($contractDetail['cardHolderName']) &&
isset($contractDetail['cardSummary']) &&
isset($contractDetail['expiryDate']) &&
isset($contractDetail['paymentMethod'])) {
$ccType = $contractDetail['paymentMethod'];
$ccTypes = $this->adyenHelper->getCcTypesAltData();
if (isset($ccTypes[$ccType])) {
$ccType = $ccTypes[$ccType]['name'];
}
$label = __(
'%1, %2, **** %3',
$ccType,
$contractDetail['cardHolderName'],
$contractDetail['cardSummary']
);
$this->setAgreementLabel($label);
}
$expiryDate = explode('/', $contractDetail['expiryDate']);
$recurringType = $this->adyenHelper->getRecurringTypeFromOneclickRecurringSetting();
$agreementData = [
'card' => [
'holderName' => $contractDetail['cardHolderName'],
'number' => $contractDetail['cardSummary'],
'expiryMonth' => $expiryDate[0],
'expiryYear' => $expiryDate[1]
],
'variant' => $contractDetail['paymentMethod'],
'contractTypes' => explode(',', $recurringType)
];
$this->setAgreementData($agreementData);
return $this;
}
}
......@@ -130,10 +130,10 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
]
]);
$recurringType = $this->_adyenHelper->getAdyenAbstractConfigData('recurring_type');
$enableOneclick = $this->_adyenHelper->getAdyenAbstractConfigData('enable_oneclick');
$canCreateBillingAgreement = false;
if ($recurringType == "ONECLICK" || $recurringType == "ONECLICK,RECURRING") {
if ($enableOneclick) {
$canCreateBillingAgreement = true;
}
......
......@@ -138,9 +138,9 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
$config['payment']['adyenOneclick']['checkoutUrl'] = $this->_adyenHelper->getCheckoutContextUrl($this->_storeManager->getStore()->getId());
$config['payment']['adyenOneclick']['locale'] = $this->_adyenHelper->getStoreLocale($this->_storeManager->getStore()->getId());
$recurringType = $this->_adyenHelper->getAdyenAbstractConfigData('recurring_type');
$enableOneclick = $this->_adyenHelper->getAdyenAbstractConfigData('enable_oneclick');
$canCreateBillingAgreement = false;
if ($recurringType == "ONECLICK" || $recurringType == "ONECLICK,RECURRING") {
if ($enableOneclick) {
$canCreateBillingAgreement = true;
}
......
......@@ -39,6 +39,7 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
const EXPIRY_MONTH = 'expiryMonth';
const EXPIRY_YEAR = 'expiryYear';
const HOLDER_NAME = 'holderName';
const VARIANT = 'variant';
/**
* @var array
......@@ -51,7 +52,8 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
self::SECURITY_CODE,
self::EXPIRY_MONTH,
self::EXPIRY_YEAR,
self::HOLDER_NAME
self::HOLDER_NAME,
self::VARIANT
];
/**
......
......@@ -34,6 +34,7 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
const RECURRING_DETAIL_REFERENCE = 'recurring_detail_reference';
const SECURITY_CODE = 'cvc';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const VARIANT = 'variant';
/**
* @var array
......@@ -41,7 +42,8 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
protected $additionalInformationList = [
self::RECURRING_DETAIL_REFERENCE,
self::SECURITY_CODE,
self::NUMBER_OF_INSTALLMENTS
self::NUMBER_OF_INSTALLMENTS,
self::VARIANT
];
/**
......
<?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\Setup;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\App\Config\Storage\WriterInterface;
/**
* Class UpgradeData
* @package Adyen\Payment\Setup
*/
class UpgradeData implements UpgradeDataInterface
{
/**
* @var WriterInterface
*/
private $configWriter;
/**
* @var ReinitableConfigInterface
*/
private $reinitableConfig;
public function __construct(
WriterInterface $configWriter,
ReinitableConfigInterface $reinitableConfig
) {
$this->configWriter = $configWriter;
$this->reinitableConfig = $reinitableConfig;
}
/**
* @param ModuleDataSetupInterface $setup
* @param ModuleContextInterface $context
*/
public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
$setup->startSetup();
if (version_compare($context->getVersion(), '2.4.4', '<')) {
$this->updateSchemaVersion244($setup);
}
$setup->endSetup();
}
/**
* Upgrade to 2.4.4
* We use new configuration options to define if you want to store the payment for oneclick or
* recurring or a combination of those in a more friendly way and make it easier to integrate with our checkout API
*
* @param ModuleDataSetupInterface $setup
*/
public function updateSchemaVersion244(ModuleDataSetupInterface $setup)
{
// convert billing agreement select box to oneclick recurring settings
$pathEnableOneclick = "payment/adyen_abstract/enable_oneclick";
$pathEnableRecurring = "payment/adyen_abstract/enable_recurring";
$configDataTable = $setup->getTable('core_config_data');
$connection = $setup->getConnection();
$select = $connection->select()
->from($configDataTable)
->where(
'path = ?',
'payment/adyen_abstract/recurring_type'
);
$configRecurringTypeValues = $connection->fetchAll($select);
foreach ($configRecurringTypeValues as $configRecurringTypeValue) {
$scope = $configRecurringTypeValue['scope'];
$scopeId = $configRecurringTypeValue['scope_id'];
switch ($configRecurringTypeValue['value']) {
case \Adyen\Payment\Model\RecurringType::ONECLICK:
$this->configWriter->save(
$pathEnableOneclick,
'1',
$scope,
$scopeId
);
$this->configWriter->save(
$pathEnableRecurring,
'0',
$scope,
$scopeId
);
break;
case \Adyen\Payment\Model\RecurringType::ONECLICK_RECURRING:
$this->configWriter->save(
$pathEnableOneclick,
'1',
$scope,
$scopeId
);
$this->configWriter->save(
$pathEnableRecurring,
'1',
$scope,
$scopeId
);
break;
case \Adyen\Payment\Model\RecurringType::RECURRING:
$this->configWriter->save(
$pathEnableOneclick,
'0',
$scope,
$scopeId
);
$this->configWriter->save(
$pathEnableRecurring,
'1',
$scope,
$scopeId
);
break;
case \Adyen\Payment\Model\RecurringType::NONE:
$this->configWriter->save(
$pathEnableOneclick,
'0',
$scope,
$scopeId
);
$this->configWriter->save(
$pathEnableRecurring,
'0',
$scope,
$scopeId
);
break;
}
}
// re-initialize otherwise it will cause errors
$this->reinitableConfig->reinit();
}
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
"name": "adyen/module-payment",
"description": "Official Magento2 Plugin to connect to Payment Service Provider Adyen.",
"type": "magento2-module",
"version": "2.4.3",
"version": "2.4.4",
"license": [
"OSL-3.0",
"AFL-3.0"
......
......@@ -22,33 +22,30 @@
* Author: Adyen <magento@adyen.com>
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="adyen_billing_agreements" translate="label" type="text" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_include.xsd">
<group id="adyen_billing_agreements" translate="label" type="text" sortOrder="50" showInDefault="1"
showInWebsite="1" showInStore="1">
<label><![CDATA[Advanced: Billing Agreements]]></label>
<frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model>
<comment>
<![CDATA[
<p>
<strong>ONECLICK</strong>: The shopper opts in to storing their card details for future use.
The shopper is present for the subsequent transaction, for cards the security code (CVC/CVV) is required.
</p>
<p>
<strong>RECURRING*</strong>: Payment details are stored for future use. For cards, the security
code (CVC/CVV) is not required for subsequent payments.
</p>
<p>
<strong>ONECLICK, RECURRING*</strong>: Payment details are stored for future use. This allows the use of
the stored payment details regardless of whether the shopper is on your site or not.
</p>
<p>* keep in mind you need the recurring permission enabled. You can contact magento@adyen.com to enable this for your account.
]]>
</comment>
<field id="enable_oneclick" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1"
showInStore="1">
<label>Enable OneClick</label>
<tooltip>The shopper opts in to storing their card details for future use. The shopper is present for the
subsequent transaction, for cards the security code (CVC/CVV) is required.
</tooltip>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_abstract/enable_oneclick</config_path>
</field>
<field id="recurring_type" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Agreement Type</label>
<tooltip>When enabled, users can save their Credit Cards and their SEPA authorizations. ONECLICK will require the input of the CVC for subsequent payments, while RECURRING does not.</tooltip>
<source_model>Adyen\Payment\Model\Config\Source\RecurringType</source_model>
<config_path>payment/adyen_abstract/recurring_type</config_path>
<field id="enable_recurring" translate="label" type="select" sortOrder="30" showInDefault="1" showInWebsite="1"
showInStore="1">
<label>Enable Recurring</label>
<tooltip>Payment details are stored for future use. For cards, the security
code (CVC/CVV) is not required for subsequent payments.
</tooltip>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_abstract/enable_recurring</config_path>
</field>
</group>
</include>
\ No newline at end of file
......@@ -28,20 +28,21 @@
<adyen_abstract>
<active>0</active>
<model>AdyenPaymentGenericFacade</model>
<recurring_type>ONECLICK</recurring_type>
<order_status>pending</order_status>
<demo_mode>0</demo_mode>
<demo_mode>1</demo_mode>
<debug>1</debug>
<title_renderer>title_image</title_renderer>
<sepa_flow>sale</sepa_flow>
<split_payments_refund_strategy>1</split_payments_refund_strategy>
<return_path>checkout/cart</return_path>
<enable_oneclick>1</enable_oneclick>
<enable_recurring>0</enable_recurring>
<group>adyen</group>
</adyen_abstract>
<adyen_cc>
<active>1</active>
<model>AdyenPaymentCcFacade</model>
<title>Adyen CreditCard</title>
<title>Credit Card</title>
<allowspecific>0</allowspecific>
<sort_order>2</sort_order>
<cctypes>AE,VI,MC,DI</cctypes>
......
......@@ -24,7 +24,7 @@
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Adyen_Payment" setup_version="2.4.3">
<module name="Adyen_Payment" setup_version="2.4.4">
<sequence>
<module name="Magento_Sales"/>
<module name="Magento_Quote"/>
......
This diff is collapsed.
......@@ -54,7 +54,9 @@ define(
'expiryYear',
'setStoreCc',
'installment',
'creditCardDetailsValid'
'creditCardDetailsValid',
'variant',
'placeOrderAllowed'
]);
return this;
......@@ -68,10 +70,8 @@ define(
*/
renderSecureFields: function() {
var self = this;
self.placeOrderAllowed(false);
self.creditCardOwner.subscribe(function () {
self.updateButton();
});
installments.setInstallments(0);
......@@ -85,8 +85,9 @@ define(
var card = checkout.create('card', {
originKey: self.getOriginKey(),
loadingContext: self.getLoadingContext(),
type: 'card',
hasHolderName: true,
holderNameRequired: true,
groupTypes: self.getAvailableCardTypeAltCodes(),
onChange: function(state) {
......@@ -134,26 +135,24 @@ define(
}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();
},
onError: function() {}
onValid: function(state) {
self.variant(state.brand);
self.creditCardNumber(state.data.encryptedCardNumber);
self.expiryMonth(state.data.encryptedExpiryMonth);
self.expiryYear(state.data.encryptedExpiryYear);
self.securityCode(state.data.encryptedSecurityCode);
self.creditCardOwner(state.data.holderName);
self.creditCardDetailsValid(true);
self.placeOrderAllowed(true);
},
onError: function(state) {
self.creditCardDetailsValid(false);
self.placeOrderAllowed(false);
}
});
card.mount(cardNode);
self.isPlaceOrderActionAllowed(false);
},
/**
* Builds the payment details part of the payment information reqeust
......@@ -164,6 +163,7 @@ define(
return {
'method': this.item.method,
additional_data: {
'card_brand': this.variant(),
'cc_type': this.creditCardType(),
'number': this.creditCardNumber(),
'cvc': this.securityCode(),
......@@ -180,19 +180,7 @@ define(
* @returns {boolean}
*/
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);
}
return this.isActive() && this.getCode() == this.isChecked() && this.isPlaceOrderActionAllowed() && this.placeOrderAllowed();
},
/**
* Custom place order function
......@@ -246,9 +234,7 @@ define(
var validate = $(form).validation() && $(form).validation('isValid');
var owner = Boolean($(form + ' #creditCardHolderName').valid());
if (!validate || !owner) {
if (!validate) {
return false;
}
......
......@@ -45,6 +45,7 @@ define(
var variant = ko.observable(null);
var paymentMethod = ko.observable(null);
var numberOfInstallments = ko.observable(null);
var isValid = ko.observable(false);
return Component.extend({
defaults: {
......@@ -141,8 +142,12 @@ define(
'creditCardExpMonth': ko.observable(creditCardExpMonth),
'creditCardExpYear': ko.observable(creditCardExpYear),
'getInstallments': ko.observableArray(installments),
'placeOrderAllowed': ko.observable(false),
isButtonActive: function() {
return self.isActive() && this.getCode() == self.isChecked() && self.isBillingAgreementChecked() && this.placeOrderAllowed();
},
/**
* @override
*/
......@@ -189,7 +194,7 @@ define(
* creates the card component,
* sets up the callbacks for card components
*/
renderSecureCVC: function() {
renderSecureCVC: function () {
var self = this;
var oneClickCardNode = document.getElementById('cvcContainer-' + self.value);
......@@ -198,12 +203,22 @@ define(
locale: self.getLocale()
});
// this should be fixed in new version of checkout card component
var hideCVC = false;
if (self.agreement_data.variant == "bcmc") {
hideCVC = true;
self.placeOrderAllowed(true);
} else if(self.agreement_data.variant == "maestro") {
// for maestro cvc is optional
self.placeOrderAllowed(true);
}
var oneClickCard = checkout
.create('card', {
originKey: self.getOriginKey(),
loadingContext: self.getLoadingContext(),
type: self.agreement_data.variant,
oneClick: true,
hideCVC: hideCVC,
// Specific for oneClick cards
details: [
......@@ -221,15 +236,32 @@ define(
}
},
onChange: function(state) {
onChange: function (state) {
if (state.isValid) {
self.encryptedCreditCardVerificationNumber = state.data.encryptedSecurityCode;
} else {
self.encryptedCreditCardVerificationNumber = '';
}
},
onValid: function (state) {
if (state.isValid) {
self.placeOrderAllowed(true);
isValid(true);
} else {
isValid(false);
}
return;
},
onError: function(data) {
self.placeOrderAllowed(false);
isValid(false);
return;
}
})
.mount(oneClickCardNode);
window.adyencheckout = oneClickCard;
},
/**
* Builds the payment details part of the payment information reqeust
......@@ -261,16 +293,8 @@ define(
var validate = $(form).validation() && $(form).validation('isValid');
// if oneclick or recurring is a card check CVC validity
var cid = true;
if (this.agreement_data.card) {
// if encrypted cvc is empty the request is not valid
if (this.hasVerification() && this.encryptedCreditCardVerificationNumber.length === 0) {
cid = false;
}
}
if (!validate || !cid) {
// bcmc does not have any cvc
if (!validate || (isValid() == false && variant() != "bcmc" && variant() != "maestro")) {
return false;
}
......
......@@ -87,7 +87,9 @@
</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>
<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"
......@@ -98,36 +100,11 @@
</div>
</div>
<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 number cardContainerField">
<div afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}" ></div>
<div afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div>
</div>
<!-- ko if: (hasInstallments())-->
<div class="field required"
......@@ -137,9 +114,9 @@
</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})},
<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: getInstallments,
......
......@@ -23,7 +23,6 @@
-->
<!-- ko foreach: getAdyenBillingAgreements() -->
<div class="payment-method" data-bind="css: {'_active': (value == $parent.isBillingAgreementChecked())}">
......@@ -63,7 +62,6 @@
</div>
<form class="form" action="#" method="post" data-bind="
attr: {'id': 'adyen_oneclick_' + value, 'data-role': 'adyen_oneclick_' + value },
mageInit: {
......@@ -73,7 +71,8 @@
'orderSaveUrl':$parent.getPlaceOrderUrl(),
}, 'validation':[]}">
<fieldset data-bind="attr: {class: 'fieldset payment items ccard ' + getCode(), id: 'payment_form_' + $parent.getCode() + '_' + value}">
<fieldset
data-bind="attr: {class: 'fieldset payment items ccard ' + getCode(), id: 'payment_form_' + $parent.getCode() + '_' + value}">
<!-- ko if: agreement_data.card -->
......@@ -87,7 +86,7 @@
</div>
<!-- ko if: hasVerification()-->
<div afterRender="renderSecureCVC()" data-bind="attr: { id: 'cvcContainer-' + value}" ></div>
<div afterRender="renderSecureCVC()" data-bind="attr: { id: 'cvcContainer-' + value}"></div>
<!-- /ko -->
<!--/ko-->
......@@ -124,21 +123,22 @@
<!-- ko if: number_of_installments.length > 0 -->
<div class="field required" data-bind="attr: {id: getCode() + '_installments_div'}, visible: getInstallments().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})},
<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}">
data-validate="{required:true}">
</select>
</div>
</div>
......@@ -160,8 +160,7 @@
data-bind="
click: placeOrder,
attr: {title: $t('Place Order')},
enable: (value == $parent.isBillingAgreementChecked())
"
enable: isButtonActive()"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
......
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