Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions Block/Adminhtml/System/Config/Field/PaymentMethodTitles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
/**
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2026 Adyen N.V. (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/

namespace Adyen\Payment\Block\Adminhtml\System\Config\Field;

use Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray;
use Magento\Framework\DataObject;
use Magento\Framework\Exception\LocalizedException;

class PaymentMethodTitles extends AbstractFieldArray
{
private ?PaymentMethodType $_paymentMethodTypeRenderer = null;

Check warning on line 20 in Block/Adminhtml/System/Config/Field/PaymentMethodTitles.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename this field "$_paymentMethodTypeRenderer" to match the regular expression ^[a-z][a-zA-Z0-9]*$.

See more on https://sonarcloud.io/project/issues?id=Adyen_adyen-magento2&issues=AZ0rFae7A2WZ1HihE3kh&open=AZ0rFae7A2WZ1HihE3kh&pullRequest=3285

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please change the property name to conform with Sonar rules?


/**
* @return PaymentMethodType
* @throws LocalizedException
*/
protected function getPaymentMethodTypeRenderer(): PaymentMethodType
{
if (!$this->_paymentMethodTypeRenderer) {
$this->_paymentMethodTypeRenderer = $this->getLayout()->createBlock(
PaymentMethodType::class,
'',
['data' => ['is_render_to_js_template' => true]]
);
}

return $this->_paymentMethodTypeRenderer;
}

/**
* @return void
* @throws LocalizedException
*/
protected function _prepareToRender(): void
{
$this->addColumn(
'payment_method_type',
[
'label' => __('Payment Method'),
'renderer' => $this->getPaymentMethodTypeRenderer(),
]
);
$this->addColumn(
'title',
[
'label' => __('Custom Title'),
'renderer' => false,
]
);

$this->_addAfter = false;
$this->_addButtonLabel = __('Add Override');
}

/**
* @param DataObject $row
* @return void
* @throws LocalizedException
*/
protected function _prepareArrayRow(DataObject $row): void
{
$options = [];
$paymentMethodType = $row->getPaymentMethodType();

if ($paymentMethodType) {
$options['option_' . $this->getPaymentMethodTypeRenderer()->calcOptionHash($paymentMethodType)]
= 'selected="selected"';
}

$row->setData('option_extra_attrs', $options);
}
}
64 changes: 64 additions & 0 deletions Block/Adminhtml/System/Config/Field/PaymentMethodType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
/**
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2025 Adyen N.V. (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/

namespace Adyen\Payment\Block\Adminhtml\System\Config\Field;

use Adyen\Payment\Model\Config\Source\PaymentMethodType as PaymentMethodTypeSource;
use Magento\Framework\View\Element\Context;
use Magento\Framework\View\Element\Html\Select;

class PaymentMethodType extends Select
{
/**
* @param Context $context
* @param PaymentMethodTypeSource $source
* @param array $data
*/
public function __construct(
Context $context,
private readonly PaymentMethodTypeSource $source,
array $data = []
) {
parent::__construct($context, $data);
}

/**
* @return string
*/
public function _toHtml(): string
{
if (!$this->getOptions()) {
foreach ($this->source->toOptionArray() as $option) {
$this->addOption($option['value'], (string) $option['label']);
}
}

return parent::_toHtml();
}

/**
* @param string $value
* @return $this
*/
public function setInputName(string $value): self
{
return $this->setName($value);
}

/**
* @param string $value
* @return $this
*/
public function setInputId(string $value): self
{
return $this->setId($value);
}
}
29 changes: 29 additions & 0 deletions Helper/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class Config
const XML_IGNORE_EXPIRE_WEBHOOK = 'ignore_expire_webhook';
const XML_ADYEN_ANALYTICS_PREFIX = "adyen_analytics";
const XML_INSTALLATION_TIME = 'installation_time';
const XML_PAYMENT_METHOD_TITLE_OVERRIDES = 'payment_method_title_overrides';

/**
* @param ScopeConfigInterface $scopeConfig
Expand Down Expand Up @@ -729,6 +730,34 @@ public function setInstallationTime(DateTimeInterface $pluginInstallationTime):
);
}

/**
* Returns the payment method title overrides configured by the merchant as a map of
* `[txVariant => customTitle]`. Returns an empty array when no overrides are configured
* or when the stored value cannot be decoded.
*
* @param int|null $storeId
* @return array<string, string>
*/
public function getPaymentMethodTitleOverrides(?int $storeId = null): array
{
$serialized = $this->getConfigData(
self::XML_PAYMENT_METHOD_TITLE_OVERRIDES,
self::XML_ADYEN_ABSTRACT_PREFIX,
$storeId
);

if (empty($serialized)) {
return [];
}

try {
$result = $this->serializer->unserialize($serialized);
return is_array($result) ? $result : [];
} catch (\InvalidArgumentException $e) {
return [];
}
}

public function getConfigData(string $field, string $xmlPrefix, ?int $storeId, bool $flag = false): mixed
{
$path = implode("/", [self::XML_PAYMENT_PREFIX, $xmlPrefix, $field]);
Expand Down
33 changes: 33 additions & 0 deletions Helper/PaymentMethods.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@ protected function fetchPaymentMethods(
return json_encode([]);
}

$responseData['paymentMethods'] = $this->applyPaymentMethodTitleOverrides(
$responseData['paymentMethods'],
(int) $store->getId()
);

$paymentMethods = $responseData['paymentMethods'];

$allowMultistoreTokens = $this->configHelper->getAllowMultistoreTokens($store->getId());
Expand Down Expand Up @@ -331,6 +336,34 @@ function ($method) use ($gatewayTokens) {
return $responseData;
}

/**
* Replaces the `name` field of each payment method in the API response with the
* merchant-configured override when one exists for the given tx-variant type.
* Methods without a configured override are left unchanged.
*
* @param array $paymentMethods
* @param int $storeId
* @return array
*/
protected function applyPaymentMethodTitleOverrides(array $paymentMethods, int $storeId): array
{
$overrides = $this->configHelper->getPaymentMethodTitleOverrides($storeId);

if (empty($overrides)) {
return $paymentMethods;
}

foreach ($paymentMethods as &$paymentMethod) {
$type = $paymentMethod['type'] ?? null;
if ($type !== null && isset($overrides[$type])) {
$paymentMethod['name'] = $overrides[$type];
}
}
unset($paymentMethod);

return $paymentMethods;
}

/**
* @return float
* @throws AdyenException
Expand Down
133 changes: 133 additions & 0 deletions Model/Config/Backend/PaymentMethodTitles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php
/**
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2026 Adyen N.V. (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/

namespace Adyen\Payment\Model\Config\Backend;

use Magento\Framework\App\Cache\TypeListInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Config\Value;
use Magento\Framework\Data\Collection\AbstractDb;
use Magento\Framework\Math\Random;
use Magento\Framework\Model\Context;
use Magento\Framework\Model\ResourceModel\AbstractResource;
use Magento\Framework\Registry;
use Magento\Framework\Serialize\SerializerInterface;

class PaymentMethodTitles extends Value
{
/**
* @param Context $context
* @param Registry $registry
* @param ScopeConfigInterface $config
* @param TypeListInterface $cacheTypeList
* @param Random $mathRandom
* @param SerializerInterface $serializer
* @param AbstractResource|null $resource
* @param AbstractDb|null $resourceCollection
* @param array $data
*/
public function __construct(
Context $context,
Registry $registry,
ScopeConfigInterface $config,
TypeListInterface $cacheTypeList,
protected readonly Random $mathRandom,
private readonly SerializerInterface $serializer,
?AbstractResource $resource = null,
?AbstractDb $resourceCollection = null,
array $data = []
) {
parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data);
}

/**
* Serialize the dynamic table rows before saving to the database.
* Duplicate payment method types are deduplicated (last row wins).
*
* @return $this
*/
public function beforeSave(): static
{
$value = $this->getValue();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would you think about adding a validator to check the uniqueness of the values? So that, each payment method can only have one override per store.


if (!is_array($value)) {
return $this;
}

$result = [];

foreach ($value as $rowData) {
if (!is_array($rowData)) {
continue;
}

$type = trim((string) ($rowData['payment_method_type'] ?? ''));
$title = trim((string) ($rowData['title'] ?? ''));

if ($type === '' || $title === '') {
continue;
}

$result[$type] = $title;
}

$this->setValue($this->serializer->serialize($result));

return $this;
}

/**
* Deserialize the stored value after loading from the database so it can
* be rendered by the AbstractFieldArray dynamic table.
*
* @return $this
*/
protected function _afterLoad(): static
{
$value = $this->getValue();

if (empty($value)) {
return $this;
}

$decoded = $this->serializer->unserialize($value);

if (!is_array($decoded)) {
return $this;
}

$this->setValue($this->encodeArrayFieldValue($decoded));

return $this;
}

/**
* Convert the stored `{type: title}` map into the row-keyed format that
* AbstractFieldArray expects for pre-population.
*
* @param array $value
* @return array
*/
protected function encodeArrayFieldValue(array $value): array
{
$result = [];

foreach ($value as $type => $title) {
$id = $this->mathRandom->getUniqueHash('_');
$result[$id] = [
'payment_method_type' => $type,
'title' => $title,
];
}

return $result;
}
}
Loading
Loading