diff --git a/Gateway/Request/CheckoutDataBuilder.php b/Gateway/Request/CheckoutDataBuilder.php
index 3c53d55ca..ef7c67225 100644
--- a/Gateway/Request/CheckoutDataBuilder.php
+++ b/Gateway/Request/CheckoutDataBuilder.php
@@ -16,6 +16,7 @@
use Adyen\Payment\Helper\Data;
use Adyen\Payment\Helper\StateData;
use Adyen\Payment\Helper\OpenInvoice;
+use Adyen\Payment\Model\Config\Source\ThreeDSFlow;
use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
use Adyen\Payment\Observer\AdyenPaymentMethodDataAssignObserver;
@@ -209,7 +210,8 @@ public function build(array $buildSubject): array
unset($requestBody['installments']);
}
- $requestBody['additionalData']['allow3DS2'] = true;
+ $requestBody['additionalData']['allow3DS2'] =
+ $this->configHelper->getThreeDSFlow($storeId) === ThreeDSFlow::THREEDS_NATIVE;
return [
'body' => $requestBody
diff --git a/Gateway/Request/RecurringVaultDataBuilder.php b/Gateway/Request/RecurringVaultDataBuilder.php
index 1e9a32426..4cac64a81 100644
--- a/Gateway/Request/RecurringVaultDataBuilder.php
+++ b/Gateway/Request/RecurringVaultDataBuilder.php
@@ -11,8 +11,10 @@
namespace Adyen\Payment\Gateway\Request;
+use Adyen\Payment\Helper\Config;
use Adyen\Payment\Helper\StateData;
use Adyen\Payment\Helper\Vault;
+use Adyen\Payment\Model\Config\Source\ThreeDSFlow;
use Adyen\Payment\Model\Ui\AdyenCcConfigProvider;
use Magento\Payment\Gateway\Data\PaymentDataObject;
use Magento\Payment\Gateway\Helper\SubjectReader;
@@ -22,13 +24,16 @@ class RecurringVaultDataBuilder implements BuilderInterface
{
private StateData $stateData;
private Vault $vaultHelper;
+ private Config $configHelper;
public function __construct(
StateData $stateData,
- Vault $vaultHelper
+ Vault $vaultHelper,
+ Config $configHelper
) {
$this->stateData = $stateData;
$this->vaultHelper = $vaultHelper;
+ $this->configHelper = $configHelper;
}
public function build(array $buildSubject): array
@@ -62,7 +67,8 @@ public function build(array $buildSubject): array
* Due to new VISA compliance requirements, holderName is added to the payments call
*/
if ($paymentMethod->getCode() === AdyenCcConfigProvider::CC_VAULT_CODE) {
- $requestBody['additionalData']['allow3DS2'] = true;
+ $requestBody['additionalData']['allow3DS2'] =
+ $this->configHelper->getThreeDSFlow($order->getStoreId()) === ThreeDSFlow::THREEDS_NATIVE;
$requestBody['paymentMethod']['holderName'] = $details['cardHolderName'] ?? null;
}
diff --git a/Helper/Config.php b/Helper/Config.php
index 6fafd8814..8657bfe26 100644
--- a/Helper/Config.php
+++ b/Helper/Config.php
@@ -56,6 +56,7 @@ class Config
const AUTO_CAPTURE_OPENINVOICE = 'auto';
const XML_RECURRING_CONFIGURATION = 'recurring_configuration';
const XML_ALLOW_MULTISTORE_TOKENS = 'allow_multistore_tokens';
+ const XML_THREEDS_FLOW = 'threeds_flow';
protected ScopeConfigInterface $scopeConfig;
private EncryptorInterface $encryptor;
@@ -576,6 +577,21 @@ public function getAllowMultistoreTokens(int $storeId = null): ?bool
);
}
+ /**
+ * Returns the preferred ThreeDS authentication type for card and card vault payments.
+ *
+ * @param int|null $storeId
+ * @return string
+ */
+ public function getThreeDSFlow(int $storeId = null): string
+ {
+ return $this->getConfigData(
+ self::XML_THREEDS_FLOW,
+ self::XML_ADYEN_CC,
+ $storeId
+ );
+ }
+
public function getConfigData(string $field, string $xmlPrefix, ?int $storeId, bool $flag = false): mixed
{
$path = implode("/", [self::XML_PAYMENT_PREFIX, $xmlPrefix, $field]);
diff --git a/Model/Config/Source/ThreeDSFlow.php b/Model/Config/Source/ThreeDSFlow.php
new file mode 100755
index 000000000..d2bebd614
--- /dev/null
+++ b/Model/Config/Source/ThreeDSFlow.php
@@ -0,0 +1,31 @@
+
+ */
+
+namespace Adyen\Payment\Model\Config\Source;
+
+use Magento\Framework\Data\OptionSourceInterface;
+
+class ThreeDSFlow implements OptionSourceInterface
+{
+ const THREEDS_NATIVE = 'native';
+ const THREEDS_REDIRECT = 'redirect';
+
+ /**
+ * @return array
+ */
+ public function toOptionArray(): array
+ {
+ return [
+ ['value' => self::THREEDS_NATIVE, 'label' => __('Native 3D Secure 2')],
+ ['value' => self::THREEDS_REDIRECT, 'label' => __('Redirect 3D Secure 2')],
+ ];
+ }
+}
diff --git a/Test/Unit/Gateway/Request/CheckoutDataBuilderTest.php b/Test/Unit/Gateway/Request/CheckoutDataBuilderTest.php
new file mode 100644
index 000000000..09de31742
--- /dev/null
+++ b/Test/Unit/Gateway/Request/CheckoutDataBuilderTest.php
@@ -0,0 +1,83 @@
+adyenHelperMock = $this->createMock(Data::class);
+ $this->stateDataMock = $this->createMock(StateData::class);
+ $this->cartRepositoryMock = $this->createMock(CartRepositoryInterface::class);
+ $this->chargedCurrencyMock = $this->createMock(ChargedCurrency::class);
+ $this->configMock = $this->createMock(Config::class);
+ $this->openInvoiceMock = $this->createMock(OpenInvoice::class);
+
+ $this->checkoutDataBuilder = new CheckoutDataBuilder(
+ $this->adyenHelperMock,
+ $this->stateDataMock,
+ $this->cartRepositoryMock,
+ $this->chargedCurrencyMock,
+ $this->configMock,
+ $this->openInvoiceMock
+ );
+
+ parent::setUp();
+ }
+
+ public function tearDown(): void
+ {
+ $this->checkoutDataBuilder = null;
+ }
+
+
+ public function testAllowThreeDSFlag()
+ {
+ $storeId = 1;
+
+ $orderMock = $this->createMock(Order::class);
+ $orderMock->method('getQuoteId')->willReturn(1);
+ $orderMock->method('getStoreId')->willReturn($storeId);
+
+ $paymentMock = $this->createMock(Payment::class);
+ $paymentMock->method('getOrder')->willReturn($orderMock);
+
+ $buildSubject = [
+ 'payment' => $this->createConfiguredMock(PaymentDataObject::class, [
+ 'getPayment' => $paymentMock
+ ])
+ ];
+
+ $this->configMock->expects($this->once())
+ ->method('getThreeDSFlow')
+ ->with($storeId)
+ ->willReturn(ThreeDSFlow::THREEDS_NATIVE);
+
+ $request = $this->checkoutDataBuilder->build($buildSubject);
+
+ $this->assertTrue($request['body']['additionalData']['allow3DS2']);
+ }
+}
diff --git a/Test/Unit/Helper/ConfigTest.php b/Test/Unit/Helper/ConfigTest.php
index 5e43d3b10..bf70dd4f4 100644
--- a/Test/Unit/Helper/ConfigTest.php
+++ b/Test/Unit/Helper/ConfigTest.php
@@ -128,4 +128,24 @@ public function testRemoveConfigData()
$this->configHelper->removeConfigData($field, $xml_prefix);
}
+
+ public function testGetThreeDSModes()
+ {
+ $storeId = PHP_INT_MAX;
+ $expectedResult = MethodInterface::ACTION_ORDER;
+ $path = sprintf(
+ "%s/%s/%s",
+ Config::XML_PAYMENT_PREFIX,
+ Config::XML_ADYEN_CC,
+ Config::XML_THREEDS_FLOW
+ );
+
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with($this->equalTo($path), $this->equalTo(ScopeInterface::SCOPE_STORE), $this->equalTo($storeId))
+ ->willReturn($expectedResult);
+
+ $result = $this->configHelper->getThreeDSFlow($storeId);
+ $this->assertEquals($expectedResult, $result);
+ }
}
diff --git a/Test/Unit/Model/Config/Source/ThreeDSModeTest.php b/Test/Unit/Model/Config/Source/ThreeDSModeTest.php
new file mode 100644
index 000000000..e7ff61dfe
--- /dev/null
+++ b/Test/Unit/Model/Config/Source/ThreeDSModeTest.php
@@ -0,0 +1,21 @@
+ ThreeDSFlow::THREEDS_NATIVE, 'label' => __('Native 3D Secure 2')],
+ ['value' => ThreeDSFlow::THREEDS_REDIRECT, 'label' => __('Redirect 3D Secure 2')],
+ ];
+
+ $this->assertEquals($expected, $threeDSModeSource->toOptionArray());
+ }
+}
diff --git a/etc/adminhtml/system/adyen_card_payments.xml b/etc/adminhtml/system/adyen_card_payments.xml
index dac3c2624..b356ad22a 100755
--- a/etc/adminhtml/system/adyen_card_payments.xml
+++ b/etc/adminhtml/system/adyen_card_payments.xml
@@ -74,5 +74,10 @@
Magento\Config\Model\Config\Source\Yesno
payment/adyen_cc/enable_click_to_pay
+
+
+ Adyen\Payment\Model\Config\Source\ThreeDSFlow
+ payment/adyen_cc/threeds_flow
+
diff --git a/etc/config.xml b/etc/config.xml
index dd7997bbd..d61cff0b2 100755
--- a/etc/config.xml
+++ b/etc/config.xml
@@ -61,6 +61,7 @@
1
1
1
+ native
adyen