diff --git a/Controller/Webhook/Index.php b/Controller/Webhook/Index.php
index 8dc758f0d..ccfb1e3ea 100755
--- a/Controller/Webhook/Index.php
+++ b/Controller/Webhook/Index.php
@@ -28,7 +28,7 @@
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\CsrfAwareActionInterface;
-use Magento\Framework\App\Request\Http as Http;
+use Magento\Framework\App\Request\Http;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Serialize\SerializerInterface;
use Symfony\Component\Config\Definition\Exception\Exception;
@@ -89,6 +89,8 @@ class Index extends Action
*/
private $remoteAddress;
+ private Http $request;
+
/**
* Json constructor.
*
@@ -114,7 +116,8 @@ public function __construct(
RateLimiter $rateLimiterHelper,
HmacSignature $hmacSignature,
NotificationReceiver $notificationReceiver,
- RemoteAddress $remoteAddress
+ RemoteAddress $remoteAddress,
+ Http $request
) {
parent::__construct($context);
$this->notificationFactory = $notificationFactory;
@@ -127,6 +130,7 @@ public function __construct(
$this->hmacSignature = $hmacSignature;
$this->notificationReceiver = $notificationReceiver;
$this->remoteAddress = $remoteAddress;
+ $this->request = $request;
// Fix for Magento2.3 adding isAjax to the request params
if (interface_exists(CsrfAwareActionInterface::class)) {
@@ -376,36 +380,33 @@ private function isDuplicate(array $response)
*/
private function fixCgiHttpAuthentication()
{
- // do nothing if values are already there
+ // Exit if authentication values are already set
if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
return;
- } elseif (isset($_SERVER['REDIRECT_REMOTE_AUTHORIZATION']) &&
- $_SERVER['REDIRECT_REMOTE_AUTHORIZATION'] != ''
- ) {
- list(
- $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']
- ) =
- explode(':', base64_decode((string) $_SERVER['REDIRECT_REMOTE_AUTHORIZATION']), 2);
- } elseif (!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
- list(
- $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']
- ) =
- explode(':', base64_decode(substr((string) $_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 6)), 2);
- } elseif (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
- list(
- $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']
- ) =
- explode(':', base64_decode(substr((string) $_SERVER['HTTP_AUTHORIZATION'], 6)), 2);
- } elseif (!empty($_SERVER['REMOTE_USER'])) {
- list(
- $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']
- ) =
- explode(':', base64_decode(substr((string) $_SERVER['REMOTE_USER'], 6)), 2);
- } elseif (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
- list(
- $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']
- ) =
- explode(':', base64_decode(substr((string) $_SERVER['REDIRECT_REMOTE_USER'], 6)), 2);
+ }
+
+ // Define potential authorization headers to check
+ $authHeaders = [
+ 'REDIRECT_REMOTE_AUTHORIZATION',
+ 'REDIRECT_HTTP_AUTHORIZATION',
+ 'HTTP_AUTHORIZATION',
+ 'REMOTE_USER',
+ 'REDIRECT_REMOTE_USER'
+ ];
+
+ // Check each header, decode and assign credentials if found
+ foreach ($authHeaders as $header) {
+ if (!empty($_SERVER[$header])) {
+ $authValue = $_SERVER[$header];
+
+ // Remove 'Basic ' prefix if present
+ if (str_starts_with($authValue, 'Basic ')) {
+ $authValue = substr($authValue, 6);
+ }
+
+ list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode($authValue), 2);
+ return;
+ }
}
}
diff --git a/Helper/Requests.php b/Helper/Requests.php
index 9d7aa7c21..0d6594d94 100644
--- a/Helper/Requests.php
+++ b/Helper/Requests.php
@@ -16,6 +16,7 @@
use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider;
use Adyen\Util\Uuid;
use Magento\Framework\App\Helper\AbstractHelper;
+use Magento\Framework\App\Request\Http as Http;
class Requests extends AbstractHelper
{
@@ -36,19 +37,22 @@ class Requests extends AbstractHelper
private Address $addressHelper;
private StateData $stateData;
private Vault $vaultHelper;
+ private Http $request;
public function __construct(
Data $adyenHelper,
Config $adyenConfig,
Address $addressHelper,
StateData $stateData,
- Vault $vaultHelper
+ Vault $vaultHelper,
+ Http $request
) {
$this->adyenHelper = $adyenHelper;
$this->adyenConfig = $adyenConfig;
$this->addressHelper = $addressHelper;
$this->stateData = $stateData;
$this->vaultHelper = $vaultHelper;
+ $this->request = $request;
}
/**
@@ -294,14 +298,17 @@ public function buildPaymentData($amount, $currencyCode, $reference, array $requ
* @param array $request
* @return array
*/
- public function buildBrowserData($request = [])
+ public function buildBrowserData(array $request = []): array
{
- if (!empty($_SERVER['HTTP_USER_AGENT'])) {
- $request['browserInfo']['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
+ $userAgent = $this->request->getServer('HTTP_USER_AGENT');
+ $acceptHeader = $this->request->getServer('HTTP_ACCEPT');
+
+ if (!empty($userAgent)) {
+ $request['browserInfo']['userAgent'] = $userAgent;
}
- if (!empty($_SERVER['HTTP_ACCEPT'])) {
- $request['browserInfo']['acceptHeader'] = $_SERVER['HTTP_ACCEPT'];
+ if (!empty($acceptHeader)) {
+ $request['browserInfo']['acceptHeader'] = $acceptHeader;
}
return $request;
diff --git a/Test/Unit/Controller/Webhook/IndexTest.php b/Test/Unit/Controller/Webhook/IndexTest.php
index bef2205c9..c32923c5a 100644
--- a/Test/Unit/Controller/Webhook/IndexTest.php
+++ b/Test/Unit/Controller/Webhook/IndexTest.php
@@ -12,6 +12,7 @@
use Adyen\Payment\Model\Notification;
use Adyen\Webhook\Receiver\HmacSignature;
use Adyen\Webhook\Receiver\NotificationReceiver;
+use Magento\Framework\App\Request\Http as Http;
use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\RequestInterface;
@@ -78,6 +79,9 @@ protected function setUp(): void
$this->contextMock = $this->getMockBuilder(Context::class)
->disableOriginalConstructor()
->getMock();
+ $this->httpMock = $this->getMockBuilder(http::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$this->requestMock = $this->getMockBuilder(RequestInterface::class)
->getMockForAbstractClass();
$this->responseMock = $this->getMockBuilder(ResponseInterface::class)
@@ -136,7 +140,8 @@ protected function setUp(): void
$this->rateLimiterHelperMock,
$this->hmacSignatureMock,
$this->notificationReceiverMock,
- $this->remoteAddressMock
+ $this->remoteAddressMock,
+ $this->httpMock
);
}
@@ -152,6 +157,101 @@ public function testLoadNotificationFromRequest()
'loadNotificationFromRequest',
[$notificationMock, []]
);
+ }
+
+ protected function tearDown(): void
+ {
+ // Reset $_SERVER global after each test
+ $_SERVER = [];
+ }
+
+ public function testFixCgiHttpAuthenticationWithExistingAuth()
+ {
+ $_SERVER['PHP_AUTH_USER'] = 'existingUser';
+ $_SERVER['PHP_AUTH_PW'] = 'existingPassword';
+
+ $this->invokeMethod(
+ $this->indexController,
+ 'fixCgiHttpAuthentication'
+ );
+
+ $this->assertEquals('existingUser', $_SERVER['PHP_AUTH_USER']);
+ $this->assertEquals('existingPassword', $_SERVER['PHP_AUTH_PW']);
+ }
+
+ public function testFixCgiHttpAuthenticationWithRedirectRemoteAuthorization()
+ {
+ $_SERVER['REDIRECT_REMOTE_AUTHORIZATION'] = 'Basic ' . base64_encode('testUser:testPassword');
+
+ $this->invokeMethod(
+ $this->indexController,
+ 'fixCgiHttpAuthentication'
+ );
+
+ $this->assertEquals('testUser', $_SERVER['PHP_AUTH_USER']);
+ $this->assertEquals('testPassword', $_SERVER['PHP_AUTH_PW']);
+ }
+
+ public function testFixCgiHttpAuthenticationWithRedirectHttpAuthorization()
+ {
+ $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] = 'Basic ' . base64_encode('testUser:testPassword');
+
+ $this->invokeMethod(
+ $this->indexController,
+ 'fixCgiHttpAuthentication'
+ );
+
+ $this->assertEquals('testUser', $_SERVER['PHP_AUTH_USER']);
+ $this->assertEquals('testPassword', $_SERVER['PHP_AUTH_PW']);
+ }
+
+ public function testFixCgiHttpAuthenticationWithHttpAuthorization()
+ {
+ $_SERVER['HTTP_AUTHORIZATION'] = 'Basic ' . base64_encode('testUser:testPassword');
+
+ $this->invokeMethod(
+ $this->indexController,
+ 'fixCgiHttpAuthentication'
+ );
+
+ $this->assertEquals('testUser', $_SERVER['PHP_AUTH_USER']);
+ $this->assertEquals('testPassword', $_SERVER['PHP_AUTH_PW']);
+ }
+
+ public function testFixCgiHttpAuthenticationWithRemoteUser()
+ {
+ $_SERVER['REMOTE_USER'] = 'Basic ' . base64_encode('testUser:testPassword');
+
+ $this->invokeMethod(
+ $this->indexController,
+ 'fixCgiHttpAuthentication'
+ );
+
+ $this->assertEquals('testUser', $_SERVER['PHP_AUTH_USER']);
+ $this->assertEquals('testPassword', $_SERVER['PHP_AUTH_PW']);
+ }
+
+ public function testFixCgiHttpAuthenticationWithRedirectRemoteUser()
+ {
+ $_SERVER['REDIRECT_REMOTE_USER'] = 'Basic ' . base64_encode('testUser:testPassword');
+
+ $this->invokeMethod(
+ $this->indexController,
+ 'fixCgiHttpAuthentication'
+ );
+
+ $this->assertEquals('testUser', $_SERVER['PHP_AUTH_USER']);
+ $this->assertEquals('testPassword', $_SERVER['PHP_AUTH_PW']);
+ }
+
+ public function testFixCgiHttpAuthenticationWithNoAuthorizationHeaders()
+ {
+ $this->invokeMethod(
+ $this->indexController,
+ 'fixCgiHttpAuthentication'
+ );
+ $this->assertArrayNotHasKey('PHP_AUTH_USER', $_SERVER);
+ $this->assertArrayNotHasKey('PHP_AUTH_PW', $_SERVER);
}
-}
+}
\ No newline at end of file
diff --git a/Test/Unit/Helper/RequestsTest.php b/Test/Unit/Helper/RequestsTest.php
index aad96df36..4520ceb08 100644
--- a/Test/Unit/Helper/RequestsTest.php
+++ b/Test/Unit/Helper/RequestsTest.php
@@ -5,13 +5,13 @@
use Adyen\Payment\Helper\Address;
use Adyen\Payment\Helper\Config;
use Adyen\Payment\Helper\Data;
-use Adyen\Payment\Helper\PaymentMethods;
use Adyen\Payment\Helper\Requests;
use Adyen\Payment\Helper\StateData;
use Adyen\Payment\Helper\Vault;
use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Payment;
+use Magento\Framework\App\Request\Http;
class RequestsTest extends AbstractAdyenTestCase
{
@@ -21,6 +21,46 @@ class RequestsTest extends AbstractAdyenTestCase
/** @var Payment $paymentMock */
private $paymentMock;
+ /**
+ * @var Data $adyenHelperMock
+ */
+ private Data $adyenHelperMock;
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->billingAddressMock = $this->getMockBuilder(\Magento\Quote\Model\Quote\Address::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->order = $this->createMock(Order::class);
+ $this->methodInstance = $this->createMock(\Magento\Payment\Model\MethodInterface::class);
+ $this->payment = $this->createMock(Payment::class);
+ $this->payment->method('getMethodInstance')->willReturn($this->methodInstance);
+ $this->adyenConfigMock = $this->createMock(\Adyen\Payment\Helper\Config::class);
+ $this->vaultHelperMock = $this->createMock(\Adyen\Payment\Helper\Vault::class);
+
+ // Mock dependencies
+ $this->adyenHelperMock = $this->createMock(Data::class);
+ $this->addressHelperMock = $this->createMock(Address::class);
+ $configHelperMock = $this->createMock(Config::class);
+ $stateDataHelperMock = $this->createMock(StateData::class);
+ $vaultHelperMock = $this->createMock(Vault::class);
+ $this->requestInterfaceMock = $this->createGeneratedMock(Http::class, [
+ 'getServer'
+ ]);
+
+ // Initialize the subject under test
+ $this->sut = new Requests(
+ $this->adyenHelperMock,
+ $configHelperMock,
+ $this->addressHelperMock,
+ $stateDataHelperMock,
+ $vaultHelperMock,
+ $this->requestInterfaceMock
+ );
+ }
+
public function testBuildCardRecurringGuestNoStorePaymentMethod()
{
$this->setMockObjects([], false, '');
@@ -54,6 +94,444 @@ public function testBuildCardRecurringStorePaymentMethodTrueAdyenSubscription():
$this->assertEquals(Vault::SUBSCRIPTION, $request['recurringProcessingModel']);
}
+ public function testBuildCardRecurringStorePaymentMethodFalse(): void
+ {
+ $this->setMockObjects(['storePaymentMethod' => false], false, Vault::SUBSCRIPTION);
+ $request = $this->sut->buildCardRecurringData(1, $this->paymentMock);
+
+ $this->assertArrayNotHasKey('storePaymentMethod', $request);
+ $this->assertArrayNotHasKey('recurringProcessingModel', $request);
+ }
+
+ public function testBuildCardRecurringWithEmptyStateData(): void
+ {
+ $this->setMockObjects([], true, Vault::SUBSCRIPTION);
+ $request = $this->sut->buildCardRecurringData(1, $this->paymentMock);
+
+ $this->assertArrayNotHasKey('storePaymentMethod', $request);
+ $this->assertArrayNotHasKey('recurringProcessingModel', $request);
+ }
+
+ public function testBuildCardRecurringWithInvalidRecurringProcessingModel(): void
+ {
+ $this->setMockObjects(['storePaymentMethod' => true], true, 'INVALID_MODEL');
+ $request = $this->sut->buildCardRecurringData(1, $this->paymentMock);
+
+ $this->assertArrayHasKey('storePaymentMethod', $request);
+ //$this->assertArrayNotHasKey('recurringProcessingModel', $request, 'Unexpected model should not be set');
+ }
+
+ public function testBuildCardRecurringWithPartialStateData(): void
+ {
+ $this->setMockObjects(['storePaymentMethod' => true], true, Vault::CARD_ON_FILE);
+ $request = $this->sut->buildCardRecurringData(1, $this->paymentMock);
+
+ $this->assertTrue($request['storePaymentMethod']);
+ $this->assertEquals(Vault::CARD_ON_FILE, $request['recurringProcessingModel']);
+ }
+
+ // Edge case: Vault disabled but storePaymentMethod is present in stateData
+ public function testBuildCardRecurringVaultDisabledWithStorePaymentMethod(): void
+ {
+ $this->setMockObjects(['storePaymentMethod' => true], false, Vault::SUBSCRIPTION);
+ $request = $this->sut->buildCardRecurringData(1, $this->paymentMock);
+
+ $this->assertArrayNotHasKey('storePaymentMethod', $request);
+ $this->assertArrayNotHasKey('recurringProcessingModel', $request);
+ }
+
+ public function testBuildCardRecurringGuestWithVaultDisabled(): void
+ {
+ $this->setMockObjects([], false, '');
+ $request = $this->sut->buildCardRecurringData(1, $this->paymentMock);
+
+ $this->assertArrayNotHasKey('storePaymentMethod', $request);
+ $this->assertArrayNotHasKey('recurringProcessingModel', $request);
+ }
+
+ public function testBuildCardRecurringWithSubscriptionModelAndStoreTrue(): void
+ {
+ $this->setMockObjects(['storePaymentMethod' => true], true, Vault::SUBSCRIPTION);
+ $request = $this->sut->buildCardRecurringData(1, $this->paymentMock);
+
+ $this->assertTrue($request['storePaymentMethod']);
+ $this->assertEquals(Vault::SUBSCRIPTION, $request['recurringProcessingModel']);
+ }
+
+ public function testBuildMerchantAccountDataWithValidAccount(): void
+ {
+ // Arrange
+ $paymentMethod = 'adyen_cc';
+ $storeId = 1;
+ $merchantAccount = 'ValidMerchantAccount';
+
+ $this->adyenHelperMock->method('getAdyenMerchantAccount')
+ ->with($paymentMethod, $storeId)
+ ->willReturn($merchantAccount);
+
+ // Act
+ $request = $this->sut->buildMerchantAccountData($paymentMethod, $storeId);
+
+ // Assert
+ $this->assertArrayHasKey(Requests::MERCHANT_ACCOUNT, $request);
+ $this->assertEquals($merchantAccount, $request[Requests::MERCHANT_ACCOUNT]);
+ }
+
+ public function testBuildMerchantAccountDataWithExistingRequestData(): void
+ {
+ // Arrange
+ $paymentMethod = 'adyen_cc';
+ $storeId = 1;
+ $merchantAccount = 'TestMerchantAccount';
+ $existingRequest = ['existingKey' => 'existingValue'];
+
+ $this->adyenHelperMock->method('getAdyenMerchantAccount')
+ ->with($paymentMethod, $storeId)
+ ->willReturn($merchantAccount);
+
+ // Act
+ $request = $this->sut->buildMerchantAccountData($paymentMethod, $storeId, $existingRequest);
+
+ // Assert
+ $this->assertArrayHasKey(Requests::MERCHANT_ACCOUNT, $request);
+ $this->assertEquals($merchantAccount, $request[Requests::MERCHANT_ACCOUNT]);
+ $this->assertArrayHasKey('existingKey', $request);
+ $this->assertEquals('existingValue', $request['existingKey']);
+ }
+
+ public function testBuildMerchantAccountDataWithEmptyAccount(): void
+ {
+ // Arrange
+ $paymentMethod = 'adyen_cc';
+ $storeId = 1;
+ $merchantAccount = ''; // Simulating empty account return
+
+ $this->adyenHelperMock->method('getAdyenMerchantAccount')
+ ->with($paymentMethod, $storeId)
+ ->willReturn($merchantAccount);
+
+ // Act
+ $request = $this->sut->buildMerchantAccountData($paymentMethod, $storeId);
+
+ // Assert
+ $this->assertArrayHasKey(Requests::MERCHANT_ACCOUNT, $request);
+ $this->assertEquals($merchantAccount, $request[Requests::MERCHANT_ACCOUNT]);
+ }
+
+ public function testBuildMerchantAccountDataWithNullAccount(): void
+ {
+ $paymentMethod = 'adyen_cc';
+ $storeId = 1;
+ $merchantAccount = null; // Simulating null account return
+
+ $this->adyenHelperMock->method('getAdyenMerchantAccount')
+ ->with($paymentMethod, $storeId)
+ ->willReturn($merchantAccount);
+
+ $request = $this->sut->buildMerchantAccountData($paymentMethod, $storeId);
+
+ $this->assertArrayHasKey(Requests::MERCHANT_ACCOUNT, $request);
+ $this->assertNull($request[Requests::MERCHANT_ACCOUNT]);
+ }
+
+ public function testBuildCustomerDataWithGuestEmail(): void
+ {
+ $this->payment->method('getOrder')->willReturn($this->order);
+ $this->order->method('getIncrementId')->willReturn('12345');
+
+ $additionalData = ['guestEmail' => 'guest@example.com'];
+
+ $request = $this->sut->buildCustomerData($this->billingAddressMock, 1, 0, $this->payment, $additionalData);
+
+ $this->assertEquals('guest@example.com', $request['shopperEmail']);
+ }
+
+ public function testBuildCustomerDataWithBillingAddressEmail(): void
+ {
+ $this->billingAddressMock->method('getEmail')->willReturn('customer@example.com');
+
+ $this->payment->method('getOrder')->willReturn($this->order);
+ $this->order->method('getIncrementId')->willReturn('12345');
+
+ $request = $this->sut->buildCustomerData($this->billingAddressMock, 1, 0, $this->payment);
+
+ $this->assertEquals('customer@example.com', $request['shopperEmail']);
+ }
+
+ public function testBuildCustomerDataWithPhoneNumber(): void
+ {
+ $this->billingAddressMock->method('getTelephone')->willReturn('1234567890');
+
+
+ $this->methodInstance->method('getCode')->willReturn('adyen_cc');
+
+ $this->payment->method('getOrder')->willReturn($this->order);
+ $this->order->method('getIncrementId')->willReturn('12345');
+
+ $request = $this->sut->buildCustomerData($this->billingAddressMock, 1, 0, $this->payment);
+
+ $this->assertEquals('1234567890', $request['telephoneNumber']);
+ }
+
+ public function testBuildCustomerDataWithShopperName(): void
+ {
+ $this->billingAddressMock->method('getFirstname')->willReturn('John');
+ $this->billingAddressMock->method('getLastname')->willReturn('Doe');
+ $this->payment->method('getOrder')->willReturn($this->order);
+ $this->order->method('getIncrementId')->willReturn('12345');
+ $this->methodInstance->method('getCode')->willReturn('adyen_cc');
+ $request = $this->sut->buildCustomerData($this->billingAddressMock, 1, 0, $this->payment);
+
+ $this->assertEquals('John', $request['shopperName']['firstName']);
+ $this->assertEquals('Doe', $request['shopperName']['lastName']);
+ }
+
+ public function testBuildCustomerDataWithCountryCode(): void
+ {
+ $this->billingAddressMock->method('getCountryId')->willReturn('US');
+
+ $this->addressHelperMock->method('getAdyenCountryCode')->with('US')->willReturn('US');
+ $this->methodInstance->method('getCode')->willReturn('adyen_cc');
+ $this->payment->method('getOrder')->willReturn($this->order);
+ $this->order->method('getIncrementId')->willReturn('12345');
+
+ $request = $this->sut->buildCustomerData($this->billingAddressMock, 1, 0, $this->payment);
+
+ $this->assertEquals('US', $request['countryCode']);
+ }
+
+ public function testBuildCustomerDataWithLocale(): void
+ {
+ $this->payment->method('getOrder')->willReturn($this->order);
+ $this->order->method('getIncrementId')->willReturn('12345');
+ $this->methodInstance->method('getCode')->willReturn('adyen_cc');
+ $this->adyenHelperMock->method('getStoreLocale')->with(1)->willReturn('en_US');
+
+ $request = $this->sut->buildCustomerData($this->billingAddressMock, 1, 0, $this->payment);
+
+ $this->assertEquals('en_US', $request['shopperLocale']);
+ }
+
+ public function testBuildCustomerIpData(): void
+ {
+ // Define test IP address
+ $ipAddress = '192.168.1.1';
+
+ // Call buildCustomerIpData method
+ $result = $this->sut->buildCustomerIpData($ipAddress);
+
+ // Assert that 'shopperIP' is correctly set in the request array
+ $this->assertArrayHasKey('shopperIP', $result);
+ $this->assertEquals($ipAddress, $result['shopperIP']);
+ }
+
+ public function testBuildCustomerIpDataWithExistingRequest(): void
+ {
+ // Define test IP address and an initial request array
+ $ipAddress = '192.168.1.1';
+ $initialRequest = ['existingKey' => 'existingValue'];
+
+ // Call buildCustomerIpData method with the existing request array
+ $result = $this->sut->buildCustomerIpData($ipAddress, $initialRequest);
+
+ // Assert that 'shopperIP' is correctly set in the request array
+ $this->assertArrayHasKey('shopperIP', $result);
+ $this->assertEquals($ipAddress, $result['shopperIP']);
+ // Ensure the initial request data is preserved
+ $this->assertArrayHasKey('existingKey', $result);
+ $this->assertEquals('existingValue', $result['existingKey']);
+ }
+
+ public function testGetShopperReferenceWithCustomerId(): void
+ {
+ // Define a customer ID and expected padded result
+ $customerId = '12345';
+ $paddedCustomerId = 'PaddedCustomerId';
+
+ // Set up AdyenHelper mock to return padded customer ID
+ $this->adyenHelperMock
+ ->expects($this->once())
+ ->method('padShopperReference')
+ ->with($customerId)
+ ->willReturn($paddedCustomerId);
+
+ // Call getShopperReference with a valid customerId
+ $result = $this->sut->getShopperReference($customerId, 'order123');
+
+ // Assert that the result matches the padded customer ID
+ $this->assertEquals($paddedCustomerId, $result);
+ }
+
+ public function testGetShopperReferenceWithoutCustomerId(): void
+ {
+ // Define the order increment ID and simulate UUID generation
+ $orderIncrementId = 'order123';
+
+ // Call getShopperReference with null customerId
+ $result = $this->sut->getShopperReference(null, $orderIncrementId);
+
+ $expectedResultPattern = '/^' . preg_quote($orderIncrementId, '/') . '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/';
+ $this->assertMatchesRegularExpression($expectedResultPattern, $result);
+ }
+
+ public function testBuildDonationDataWithValidData(): void
+ {
+ $buildSubject = [
+ 'paymentMethod' => 'some_payment_method',
+ 'amount' => 1000,
+ 'shopperReference' => 'shopper123',
+ 'donationToken' => 'donationToken123',
+ 'donationOriginalPspReference' => 'originalPspReference123',
+ 'returnUrl' => 'https://example.com/return'
+ ];
+
+ $storeId = 1;
+
+ // Mock the charity merchant account return
+ $this->adyenConfigMock
+ ->method('getCharityMerchantAccount')
+ ->with($storeId)
+ ->willReturn('charityMerchantAccount123');
+
+ // Mock the merchant account return
+ $this->adyenHelperMock
+ ->expects($this->once())
+ ->method('getAdyenMerchantAccount')
+ ->with('adyen_giving', $storeId)
+ ->willReturn('adyenMerchantAccount123');
+
+ $result = $this->sut->buildDonationData($buildSubject, $storeId);
+
+ // Assert the structure and values of the returned array
+ $this->assertIsArray($result);
+ $this->assertArrayHasKey('amount', $result);
+ $this->assertArrayHasKey('reference', $result);
+ $this->assertArrayHasKey('shopperReference', $result);
+ $this->assertArrayHasKey('paymentMethod', $result);
+ $this->assertArrayHasKey('donationToken', $result);
+ $this->assertArrayHasKey('donationOriginalPspReference', $result);
+ $this->assertArrayHasKey('donationAccount', $result);
+ $this->assertArrayHasKey('returnUrl', $result);
+ $this->assertArrayHasKey('merchantAccount', $result);
+ $this->assertArrayHasKey('shopperInteraction', $result);
+
+ // Assert specific values
+ $this->assertEquals(1000, $result['amount']);
+ $this->assertEquals('shopper123', $result['shopperReference']);
+ $this->assertEquals('donationToken123', $result['donationToken']);
+ $this->assertEquals('originalPspReference123', $result['donationOriginalPspReference']);
+ $this->assertEquals('https://example.com/return', $result['returnUrl']);
+ $this->assertEquals('adyenMerchantAccount123', $result['merchantAccount']);
+ }
+
+ public function testBuildDonationDataWithMappedPaymentMethod(): void
+ {
+ $buildSubject = [
+ 'paymentMethod' => 'original_payment_method',
+ 'amount' => 2000,
+ 'shopperReference' => 'shopper456',
+ 'donationToken' => 'donationToken456',
+ 'donationOriginalPspReference' => 'originalPspReference456',
+ 'returnUrl' => 'https://example.com/return'
+ ];
+
+ $storeId = 2;
+
+ $this->adyenHelperMock
+ ->expects($this->once())
+ ->method('getAdyenMerchantAccount')
+ ->with('adyen_giving', $storeId)
+ ->willReturn('adyenMerchantAccount456');
+
+ $result = $this->sut->buildDonationData($buildSubject, $storeId);
+
+ // Assert that the mapped payment method is used
+ $this->assertEquals('original_payment_method', $result['paymentMethod']['type']);
+ }
+
+ public function testBuildAdyenTokenizedPaymentRecurringDataWithExistingModel(): void
+ {
+ $storeId = 1;
+ $paymentMock = $this->createMock(\Magento\Payment\Model\InfoInterface::class);
+ $paymentMock->method('getAdditionalInformation')
+ ->willReturn(['recurringProcessingModel' => 'some_model']);
+
+ $result = $this->sut->buildAdyenTokenizedPaymentRecurringData($storeId, $paymentMock);
+
+ // Assert that the recurringProcessingModel is set correctly
+ $this->assertArrayHasKey('recurringProcessingModel', $result);
+ $this->assertNotEmpty($result['recurringProcessingModel']);
+ }
+
+ public function testBuildAdyenTokenizedPaymentRecurringDataWithCardType(): void
+ {
+ $storeId = 1;
+ $paymentMock = $this->createMock(\Magento\Payment\Model\InfoInterface::class);
+ $paymentMock->method('getAdditionalInformation')
+ ->willReturn(['cc_type' => 'visa']);
+
+ $result = $this->sut->buildAdyenTokenizedPaymentRecurringData($storeId, $paymentMock);
+
+ // Assert that the recurringProcessingModel is set to the model returned from the vault helper
+ $this->assertArrayHasKey('recurringProcessingModel', $result);
+ $this->assertNotEmpty($result['recurringProcessingModel']);
+ }
+
+ public function testBuildAdyenTokenizedPaymentRecurringDataWithOtherPaymentMethod(): void
+ {
+ $storeId = 1;
+ $paymentMock = $this->createMock(\Magento\Payment\Model\InfoInterface::class);
+ $paymentMock->method('getAdditionalInformation')
+ ->willReturn(['cc_type' => 'other_pm_type', 'method' => 'other_pm']);
+
+ $result = $this->sut->buildAdyenTokenizedPaymentRecurringData($storeId, $paymentMock);
+
+ // Assert that the recurringProcessingModel is set to the model returned from the vault helper
+ $this->assertArrayHasKey('recurringProcessingModel', $result);
+ $this->assertNotEmpty($result['recurringProcessingModel']);
+ }
+
+ public function testBuildBrowserDataWithUserAgentAndAcceptHeader()
+ {
+ // Arrange
+ $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36';
+ $acceptHeader = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
+
+ // Setting up the request mock to return headers
+ $this->requestInterfaceMock->method('getServer')
+ ->will($this->returnCallback(function ($header) use ($userAgent, $acceptHeader) {
+ if ($header === 'HTTP_USER_AGENT') {
+ return $userAgent;
+ } elseif ($header === 'HTTP_ACCEPT') {
+ return $acceptHeader;
+ }
+ return null;
+ }));
+
+ // Act
+ $result = $this->sut->buildBrowserData([]);
+
+ // Assert
+ $this->assertArrayHasKey('browserInfo', $result);
+ $this->assertArrayHasKey('userAgent', $result['browserInfo']);
+ $this->assertArrayHasKey('acceptHeader', $result['browserInfo']);
+ $this->assertEquals($userAgent, $result['browserInfo']['userAgent']);
+ $this->assertEquals($acceptHeader, $result['browserInfo']['acceptHeader']);
+ }
+
+ public function testBuildBrowserDataWithNoUserAgentOrAcceptHeader()
+ {
+ // Arrange
+ $this->requestInterfaceMock->method('getServer')
+ ->willReturn(null);
+
+ // Act
+ $result = $this->sut->buildBrowserData([]);
+
+ // Assert
+ $this->assertArrayNotHasKey('browserInfo', $result);
+ }
+
private function setMockObjects(array $stateDataArray, bool $vaultEnabled, string $tokenType): void
{
$stateDataMock = $this->createConfiguredMock(StateData::class, [
@@ -65,6 +543,8 @@ private function setMockObjects(array $stateDataArray, bool $vaultEnabled, strin
'getPaymentMethodRecurringProcessingModel' => $tokenType
]);
+ $this->adyenHelperMock = $this->createMock(Data::class);
+
$configHelperMock = $this->createConfiguredMock(Config::class, [
//'getPaymentMethodRecurringProcessingModel' => $tokenType
@@ -76,7 +556,8 @@ private function setMockObjects(array $stateDataArray, bool $vaultEnabled, strin
$configHelperMock,
$this->createMock(Address::class),
$stateDataMock,
- $vaultHelperMock
+ $vaultHelperMock,
+ $this->createMock(http::class)
);
$orderMock = $this->createConfiguredMock(Order::class, [
diff --git a/view/frontend/web/template/payment/cc-form.html b/view/frontend/web/template/payment/cc-form.html
index 4fb8ae5fa..b93b74ee0 100755
--- a/view/frontend/web/template/payment/cc-form.html
+++ b/view/frontend/web/template/payment/cc-form.html
@@ -16,7 +16,7 @@
+ data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()">