Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 33 additions & 0 deletions src/Provider/SupportedMethodsProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ public function provide(
array $supportedMethods,
string $factoryName,
int $paymentAmount,
?string $billingCountryCode = null,
): array {
$activeCurrencyCode = $this->currencyContext->getCurrencyCode();
$authorizedCurrencies = null;
$allowedCountries = null;

foreach ($supportedMethods as $key => $paymentMethod) {
Assert::isInstanceOf($paymentMethod, PaymentMethodInterface::class);
Expand All @@ -37,6 +39,13 @@ public function provide(
}

$authorizedCurrencies ??= $this->resolveAuthorizedCurrencies($factoryName);
$allowedCountries ??= $this->resolveAllowedCountries($factoryName);

if ($billingCountryCode !== null && $allowedCountries !== [] && !\in_array($billingCountryCode, $allowedCountries, true)) {
unset($supportedMethods[$key]);

continue;
}

if (!\array_key_exists($activeCurrencyCode, $authorizedCurrencies)) {
unset($supportedMethods[$key]);
Expand Down Expand Up @@ -93,4 +102,28 @@ private function resolveAuthorizedCurrencies(string $factoryName): array

return $currencies;
}

private function resolveAllowedCountries(string $factoryName): array
{
$underscorePos = strpos($factoryName, '_');
if ($underscorePos === false) {
return [];
}

$account = $this->clientFactory->create($factoryName)->getAccount();
$pmKey = substr($factoryName, $underscorePos + 1);
$paymentMethods = $account['payment_methods'] ?? [];
Assert::isArray($paymentMethods);
$pmData = $paymentMethods[$pmKey] ?? [];
Assert::isArray($pmData);

$allowedCountries = $pmData['allowed_countries'] ?? [];
Assert::isArray($allowedCountries);

if (\in_array('ALL', $allowedCountries, true)) {
return [];
}

return $allowedCountries;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Provider\SupportedMethodsProvider;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\Payment;
use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
Expand All @@ -28,10 +29,15 @@ public function getSupportedMethods(BasePaymentInterface $subject): array
Assert::isInstanceOf($subject, Payment::class);
$supportedMethods = $this->decorated->getSupportedMethods($subject);

/** @var OrderInterface $order */
$order = $subject->getOrder();
$billingCountryCode = $order->getBillingAddress()?->getCountryCode();

return $this->supportedMethodsProvider->provide(
$supportedMethods,
AmericanExpressGatewayFactory::FACTORY_NAME,
$subject->getAmount() ?? 0,
$billingCountryCode,
);
}

Expand Down
6 changes: 6 additions & 0 deletions src/Resolver/ApplePayPaymentMethodsResolverDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PayPlug\SyliusPayPlugPlugin\Gateway\ApplePayGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Provider\SupportedMethodsProvider;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\Payment;
use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
Expand All @@ -28,10 +29,15 @@ public function getSupportedMethods(BasePaymentInterface $subject): array
Assert::isInstanceOf($subject, Payment::class);
$supportedMethods = $this->decorated->getSupportedMethods($subject);

/** @var OrderInterface $order */
$order = $subject->getOrder();
$billingCountryCode = $order->getBillingAddress()?->getCountryCode();

return $this->supportedMethodsProvider->provide(
$supportedMethods,
ApplePayGatewayFactory::FACTORY_NAME,
$subject->getAmount() ?? 0,
$billingCountryCode,
);
}

Expand Down
6 changes: 6 additions & 0 deletions src/Resolver/BancontactPaymentMethodsResolverDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Provider\SupportedMethodsProvider;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\Payment;
use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
Expand All @@ -28,10 +29,15 @@ public function getSupportedMethods(BasePaymentInterface $subject): array
Assert::isInstanceOf($subject, Payment::class);
$supportedMethods = $this->decorated->getSupportedMethods($subject);

/** @var OrderInterface $order */
$order = $subject->getOrder();
$billingCountryCode = $order->getBillingAddress()?->getCountryCode();

return $this->supportedMethodsProvider->provide(
$supportedMethods,
BancontactGatewayFactory::FACTORY_NAME,
$subject->getAmount() ?? 0,
$billingCountryCode,
);
}

Expand Down
6 changes: 6 additions & 0 deletions src/Resolver/PayPlugPaymentMethodsResolverDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Provider\SupportedMethodsProvider;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\Payment;
use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
Expand All @@ -28,10 +29,15 @@ public function getSupportedMethods(BasePaymentInterface $subject): array
Assert::isInstanceOf($subject, Payment::class);
$supportedMethods = $this->decorated->getSupportedMethods($subject);

/** @var OrderInterface $order */
$order = $subject->getOrder();
$billingCountryCode = $order->getBillingAddress()?->getCountryCode();

return $this->supportedMethodsProvider->provide(
$supportedMethods,
PayPlugGatewayFactory::FACTORY_NAME,
$subject->getAmount() ?? 0,
$billingCountryCode,
);
}

Expand Down
6 changes: 6 additions & 0 deletions src/Resolver/ScalapayPaymentMethodsResolverDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PayPlug\SyliusPayPlugPlugin\Gateway\ScalapayGatewayFactory;
use PayPlug\SyliusPayPlugPlugin\Provider\SupportedMethodsProvider;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\Payment;
use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
Expand All @@ -28,10 +29,15 @@ public function getSupportedMethods(BasePaymentInterface $subject): array
Assert::isInstanceOf($subject, Payment::class);
$supportedMethods = $this->decorated->getSupportedMethods($subject);

/** @var OrderInterface $order */
$order = $subject->getOrder();
$billingCountryCode = $order->getBillingAddress()?->getCountryCode();

return $this->supportedMethodsProvider->provide(
$supportedMethods,
ScalapayGatewayFactory::FACTORY_NAME,
$subject->getAmount() ?? 0,
$billingCountryCode,
);
}

Expand Down
80 changes: 79 additions & 1 deletion tests/PHPUnit/Provider/SupportedMethodsProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ protected function setUp(): void
public function testProvide_withDifferentFactory_doesNotFilter(): void
{
$this->currencyContext->method('getCurrencyCode')->willReturn('EUR');
$this->apiClient->method('getAccount')->willReturn($this->buildAccount(30, 2000000));
// getAccount() must never be called: the PayPlug method never matches the Bancontact factory,
// so the loop always hits `continue` before reaching the lazy-loading lines.
$this->apiClient->expects(self::never())->method('getAccount');

// PaymentMethod is PayPlug, but we're querying for Bancontact — so it's passed through as-is
$method = $this->buildPaymentMethod(PayPlugGatewayFactory::FACTORY_NAME);
Expand Down Expand Up @@ -206,6 +208,82 @@ public function testProvide_withMixedList_filtersCorrectly(): void
self::assertCount(2, $result); // Bancontact not removed (no filter applied for different factory)
}

// -------------------------------------------------------------------------
// provide() — allowed_countries filter
// -------------------------------------------------------------------------

/**
* Billing country is in the allowed_countries list → method kept.
*/
public function testProvide_withAllowedCountry_keepsMethod(): void
{
$this->currencyContext->method('getCurrencyCode')->willReturn('EUR');
$account = [
'configuration' => ['min_amounts' => ['EUR' => 30], 'max_amounts' => ['EUR' => 2000000]],
'payment_methods' => ['scalapay' => ['min_amounts' => ['EUR' => 500], 'max_amounts' => ['EUR' => 200000], 'allowed_countries' => ['FR', 'DE']]],
];
$this->apiClient->method('getAccount')->willReturn($account);

$method = $this->buildPaymentMethod('payplug_scalapay');
$result = $this->provider->provide([$method], 'payplug_scalapay', 1000, 'FR');

self::assertCount(1, $result);
}

/**
* Billing country is NOT in the allowed_countries list → method removed.
*/
public function testProvide_withDisallowedCountry_removesMethod(): void
{
$this->currencyContext->method('getCurrencyCode')->willReturn('EUR');
$account = [
'configuration' => ['min_amounts' => ['EUR' => 30], 'max_amounts' => ['EUR' => 2000000]],
'payment_methods' => ['scalapay' => ['min_amounts' => ['EUR' => 500], 'max_amounts' => ['EUR' => 200000], 'allowed_countries' => ['FR', 'DE']]],
];
$this->apiClient->method('getAccount')->willReturn($account);

$method = $this->buildPaymentMethod('payplug_scalapay');
$result = $this->provider->provide([$method], 'payplug_scalapay', 1000, 'US');

self::assertEmpty($result);
}

/**
* allowed_countries = ["ALL"] → country check skipped, method kept.
*/
public function testProvide_withAllowedCountriesAll_keepsMethod(): void
{
$this->currencyContext->method('getCurrencyCode')->willReturn('EUR');
$account = [
'configuration' => ['min_amounts' => ['EUR' => 30], 'max_amounts' => ['EUR' => 2000000]],
'payment_methods' => ['bancontact' => ['min_amounts' => ['EUR' => 30], 'max_amounts' => ['EUR' => 2000000], 'allowed_countries' => ['ALL']]],
];
$this->apiClient->method('getAccount')->willReturn($account);

$method = $this->buildPaymentMethod('payplug_bancontact');
$result = $this->provider->provide([$method], 'payplug_bancontact', 1000, 'US');

self::assertCount(1, $result);
}

/**
* Billing country is null (no billing address yet) → country check skipped, method kept.
*/
public function testProvide_withNullBillingCountry_keepsMethod(): void
{
$this->currencyContext->method('getCurrencyCode')->willReturn('EUR');
$account = [
'configuration' => ['min_amounts' => ['EUR' => 30], 'max_amounts' => ['EUR' => 2000000]],
'payment_methods' => ['scalapay' => ['min_amounts' => ['EUR' => 500], 'max_amounts' => ['EUR' => 200000], 'allowed_countries' => ['FR', 'DE']]],
];
$this->apiClient->method('getAccount')->willReturn($account);

$method = $this->buildPaymentMethod('payplug_scalapay');
$result = $this->provider->provide([$method], 'payplug_scalapay', 1000, null);

self::assertCount(1, $result);
}

// -------------------------------------------------------------------------
// provide() — payment method specific amounts used over configuration defaults
// -------------------------------------------------------------------------
Expand Down