Skip to content

Commit

Permalink
Merge branch 'main' into patch-4
Browse files Browse the repository at this point in the history
  • Loading branch information
candemiralp authored Nov 14, 2024
2 parents 2006128 + d44093a commit d22e2cc
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 3 deletions.
4 changes: 3 additions & 1 deletion Gateway/Request/CheckoutDataBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions Gateway/Request/RecurringVaultDataBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
16 changes: 16 additions & 0 deletions Helper/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]);
Expand Down
31 changes: 31 additions & 0 deletions Model/Config/Source/ThreeDSFlow.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/**
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2024 Adyen N.V. (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <[email protected]>
*/

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')],
];
}
}
83 changes: 83 additions & 0 deletions Test/Unit/Gateway/Request/CheckoutDataBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace Adyen\Payment\Test\Gateway\Request;

use Adyen\Payment\Gateway\Request\CheckoutDataBuilder;
use Adyen\Payment\Helper\ChargedCurrency;
use Adyen\Payment\Helper\Config;
use Adyen\Payment\Helper\Data;
use Adyen\Payment\Helper\OpenInvoice;
use Adyen\Payment\Helper\StateData;
use Adyen\Payment\Model\Config\Source\ThreeDSFlow;
use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;
use Magento\Payment\Gateway\Data\PaymentDataObject;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Payment;
use PHPUnit\Framework\MockObject\MockObject;

class CheckoutDataBuilderTest extends AbstractAdyenTestCase
{
protected ?CheckoutDataBuilder $checkoutDataBuilder;

protected Data|MockObject $adyenHelperMock;
protected StateData|MockObject $stateDataMock;
protected CartRepositoryInterface|MockObject $cartRepositoryMock;
protected ChargedCurrency|MockObject $chargedCurrencyMock;
protected Config|MockObject $configMock;
protected OpenInvoice|MockObject $openInvoiceMock;

public function setUp(): void
{
$this->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']);
}
}
20 changes: 20 additions & 0 deletions Test/Unit/Helper/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
21 changes: 21 additions & 0 deletions Test/Unit/Model/Config/Source/ThreeDSModeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Adyen\Payment\Test\Unit\Model\Config\Source;

use Adyen\Payment\Model\Config\Source\ThreeDSFlow;
use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;

class ThreeDSModeTest extends AbstractAdyenTestCase
{
public function testToOptionArray()
{
$threeDSModeSource = new ThreeDSFlow();

$expected = [
['value' => ThreeDSFlow::THREEDS_NATIVE, 'label' => __('Native 3D Secure 2')],
['value' => ThreeDSFlow::THREEDS_REDIRECT, 'label' => __('Redirect 3D Secure 2')],
];

$this->assertEquals($expected, $threeDSModeSource->toOptionArray());
}
}
5 changes: 5 additions & 0 deletions etc/adminhtml/system/adyen_card_payments.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,10 @@
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_cc/enable_click_to_pay</config_path>
</field>
<field id="threeds_flow" translate="label" type="select" sortOrder="50" showInDefault="1" showInWebsite="1">
<label>3D Secure 2 authentication flow</label>
<source_model>Adyen\Payment\Model\Config\Source\ThreeDSFlow</source_model>
<config_path>payment/adyen_cc/threeds_flow</config_path>
</field>
</group>
</include>
1 change: 1 addition & 0 deletions etc/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<can_authorize_vault>1</can_authorize_vault>
<can_capture_vault>1</can_capture_vault>
<supports_recurring>1</supports_recurring>
<threeds_flow>native</threeds_flow>
<group>adyen</group>
</adyen_cc>
<adyen_cc_vault>
Expand Down

0 comments on commit d22e2cc

Please sign in to comment.