Skip to content

Commit

Permalink
Respect Tpay payment channel constraints when displaying available pa…
Browse files Browse the repository at this point in the history
…yment methods (#226)
  • Loading branch information
lchrusciel authored Dec 11, 2024
2 parents a4aff97 + 8d06567 commit 88c81b8
Show file tree
Hide file tree
Showing 17 changed files with 714 additions and 3 deletions.
20 changes: 20 additions & 0 deletions config/services/pay_by_link_payment/checker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\Checker\PaymentMethodSupportedForOrderChecker;
use CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\Checker\PaymentMethodSupportedForOrderCheckerInterface;

return static function(ContainerConfigurator $container): void {
$services = $container->services();

$services->set('commerce_weavers_sylius_tpay.pay_by_link_payment.checker.payment_method_supported_for_order', PaymentMethodSupportedForOrderChecker::class)
->args([
service('payum.dynamic_gateways.cypher'),
service('commerce_weavers_sylius_tpay.tpay.provider.order_aware_validated_tpay_api_bank_list'),
])
->alias(PaymentMethodSupportedForOrderCheckerInterface::class, 'commerce_weavers_sylius_tpay.pay_by_link_payment.checker.payment_method_supported_for_order')
;
};
1 change: 1 addition & 0 deletions config/services/pay_by_link_payment/context_provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
$services->set('commerce_weavers_sylius_tpay.pay_by_link_payment.context_provider.bank_list', BankListContextProvider::class)
->args([
service('commerce_weavers_sylius_tpay.tpay.provider.validated_tpay_api_bank_list'),
service('commerce_weavers_sylius_tpay.tpay.provider.order_aware_validated_tpay_api_bank_list'),
service('payum.dynamic_gateways.cypher'),
])
->tag('sylius.ui.template_event.context_provider')
Expand Down
9 changes: 9 additions & 0 deletions config/services/payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use CommerceWeavers\SyliusTpayPlugin\Payment\Canceller\PaymentCancellerInterface;
use CommerceWeavers\SyliusTpayPlugin\Payment\Checker\PaymentCancellationPossibilityChecker;
use CommerceWeavers\SyliusTpayPlugin\Payment\Checker\PaymentCancellationPossibilityCheckerInterface;
use CommerceWeavers\SyliusTpayPlugin\Payment\Resolver\OrderBasedPaymentMethodsResolver;

return static function(ContainerConfigurator $container): void {
$services = $container->services();
Expand All @@ -27,4 +28,12 @@
])
->alias(PaymentCancellationPossibilityCheckerInterface::class, 'commerce_weavers_sylius_tpay.payment.checker.payment_cancellation_possibility')
;

$services->set('commerce_weavers_sylius_tpay.payment.resolver.order_based_payment_methods', OrderBasedPaymentMethodsResolver::class)
->args([
service('sylius.payment_methods_resolver.channel_based'),
service('commerce_weavers_sylius_tpay.pay_by_link_payment.checker.payment_method_supported_for_order'),
])
->tag('sylius.payment_method_resolver', ['type' => 'tpay_order_based', 'label' => 'commerce_weavers_sylius_tpay.payment_methods_resolver.order_based', 'priority' => 2])
;
};
9 changes: 9 additions & 0 deletions config/services/tpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
use CommerceWeavers\SyliusTpayPlugin\Tpay\Factory\CreateVisaMobilePaymentPayloadFactoryInterface;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\AvailableTpayChannelListProvider;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\AvailableTpayChannelListProviderInterface;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\OrderAwareValidTpayChannelListProvider;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\OrderAwareValidTpayChannelListProviderInterface;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\ValidTpayChannelListProvider;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\ValidTpayChannelListProviderInterface;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Resolver\CachedTpayTransactionChannelResolver;
Expand Down Expand Up @@ -158,6 +160,13 @@
->alias(AvailableTpayChannelListProviderInterface::class, 'commerce_weavers_sylius_tpay.tpay.provider.available_tpay_api_bank_list')
;

$services->set('commerce_weavers_sylius_tpay.tpay.provider.order_aware_validated_tpay_api_bank_list', OrderAwareValidTpayChannelListProvider::class)
->args([
service('commerce_weavers_sylius_tpay.tpay.provider.validated_tpay_api_bank_list'),
])
->alias(OrderAwareValidTpayChannelListProviderInterface::class, 'commerce_weavers_sylius_tpay.tpay.provider.order_aware_validated_tpay_api_bank_list')
;

$services->set('commerce_weavers_sylius_tpay.tpay.provider.validated_tpay_api_bank_list', ValidTpayChannelListProvider::class)
->args([
service('commerce_weavers_sylius_tpay.tpay.provider.available_tpay_api_bank_list'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\Checker;

use CommerceWeavers\SyliusTpayPlugin\Tpay\GatewayName;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\OrderAwareValidTpayChannelListProviderInterface;
use Payum\Core\Security\CryptedInterface;
use Payum\Core\Security\CypherInterface;
use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;

final class PaymentMethodSupportedForOrderChecker implements PaymentMethodSupportedForOrderCheckerInterface
{
public function __construct(
private readonly CypherInterface $cypher,
private readonly OrderAwareValidTpayChannelListProviderInterface $orderAwareValidTpayChannelListProvider,
) {
}

public function isSupportedForOrder(PaymentMethodInterface $paymentMethod, OrderInterface $order): bool
{
/** @var GatewayConfigInterface|null $gatewayConfig */
$gatewayConfig = $paymentMethod->getGatewayConfig();

if (null === $gatewayConfig || GatewayName::PAY_BY_LINK !== $gatewayConfig->getFactoryName()) {
return true;
}

if ($gatewayConfig instanceof CryptedInterface) {
$gatewayConfig->decrypt($this->cypher);
}

$tpayChannelId = $gatewayConfig->getConfig()['tpay_channel_id'] ?? null;

if (null === $tpayChannelId) {
return true;
}

$validTpayChannelList = $this->orderAwareValidTpayChannelListProvider->provide($order);

return isset($validTpayChannelList[$tpayChannelId]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\Checker;

use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;

interface PaymentMethodSupportedForOrderCheckerInterface
{
public function isSupportedForOrder(PaymentMethodInterface $paymentMethod, OrderInterface $order): bool;
}
13 changes: 12 additions & 1 deletion src/PayByLinkPayment/ContextProvider/BankListContextProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\ContextProvider;

use CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\Payum\Factory\GatewayFactory as PayByLinkGatewayFactory;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\OrderAwareValidTpayChannelListProviderInterface;
use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\ValidTpayChannelListProviderInterface;
use Payum\Core\Model\GatewayConfigInterface;
use Payum\Core\Security\CryptedInterface;
Expand All @@ -23,6 +24,7 @@ final class BankListContextProvider implements ContextProviderInterface

public function __construct(
private readonly ValidTpayChannelListProviderInterface $validTpayChannelListProvider,
private readonly OrderAwareValidTpayChannelListProviderInterface $orderAwareValidTpayChannelListProvider,
private readonly CypherInterface $cypher,
) {
}
Expand Down Expand Up @@ -53,7 +55,16 @@ public function provide(array $templateContext, TemplateBlock $templateBlock): a
$tpayChannelId = $decryptedGatewayConfig['tpay_channel_id'] ?? null;

$templateContext['defaultTpayChannelId'] = $tpayChannelId;
$templateContext['banks'] = null === $tpayChannelId ? $this->validTpayChannelListProvider->provide() : [];

if (null === $tpayChannelId) {
/** @var OrderInterface|null $order */
$order = $templateContext['order'] ?? null;

$templateContext['banks'] = null === $order
? $this->validTpayChannelListProvider->provide()
: $this->orderAwareValidTpayChannelListProvider->provide($order)
;
}

return $templateContext;
}
Expand Down
48 changes: 48 additions & 0 deletions src/Payment/Resolver/OrderBasedPaymentMethodsResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\Payment\Resolver;

use CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\Checker\PaymentMethodSupportedForOrderCheckerInterface;
use Sylius\Component\Core\Model\PaymentInterface as CorePaymentInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Component\Payment\Model\PaymentInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
use Webmozart\Assert\Assert;

final class OrderBasedPaymentMethodsResolver implements PaymentMethodsResolverInterface
{
public function __construct(
private readonly PaymentMethodsResolverInterface $paymentMethodsResolver,
private readonly PaymentMethodSupportedForOrderCheckerInterface $paymentMethodSupportedForOrderChecker,
) {
}

public function getSupportedMethods(PaymentInterface $subject): array
{
Assert::isInstanceOf($subject, CorePaymentInterface::class);
Assert::true($this->supports($subject), 'This payment method is not support by resolver');

/** @var PaymentMethodInterface[] $supportedMethods */
$supportedMethods = $this->paymentMethodsResolver->getSupportedMethods($subject);

foreach ($supportedMethods as $key => $supportedMethod) {
$order = $subject->getOrder();
Assert::notNull($order);

if ($this->paymentMethodSupportedForOrderChecker->isSupportedForOrder($supportedMethod, $order)) {
continue;
}

unset($supportedMethods[$key]);
}

return array_values($supportedMethods);
}

public function supports(PaymentInterface $subject): bool
{
return $this->paymentMethodsResolver->supports($subject);
}
}
47 changes: 47 additions & 0 deletions src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\Tpay\Provider;

use Sylius\Component\Core\Model\OrderInterface;

final class OrderAwareValidTpayChannelListProvider implements OrderAwareValidTpayChannelListProviderInterface
{
private const FLOAT_AMOUNT_VALUE_TO_INT_MULTIPLIER = 100;

public function __construct(private readonly ValidTpayChannelListProviderInterface $validTpayChannelListProvider)
{
}

public function provide(OrderInterface $order): array
{
$orderTotal = $order->getTotal();
$channelList = $this->validTpayChannelListProvider->provide();

foreach ($channelList as $key => $channel) {
foreach ($channel['constraints'] ?? [] as $constraint) {
$constraintField = $constraint['field'] ?? null;
$constraintValue = $constraint['value'] ?? null;
$constraintType = $constraint['type'] ?? null;

if ('amount' !== $constraintField || null == $constraintValue || null === $constraintType) {
continue;
}

$constraintIntValue = (int) ($constraintValue * self::FLOAT_AMOUNT_VALUE_TO_INT_MULTIPLIER);

if (
('min' === $constraintType && $orderTotal < $constraintIntValue) ||
('max' === $constraintType && $orderTotal > $constraintIntValue)
) {
unset($channelList[$key]);

break;
}
}
}

return $channelList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\Tpay\Provider;

use Sylius\Component\Core\Model\OrderInterface;

interface OrderAwareValidTpayChannelListProviderInterface
{
public function provide(OrderInterface $order): array;
}
44 changes: 44 additions & 0 deletions tests/E2E/Resources/fixtures/common/payment_method.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ Sylius\Component\Core\Model\PaymentMethod:
translations:
- '@tpay_pbl_one_channel_payment_method_translation'
channels: [ '@channel_web' ]
tpay_pbl_one_channel_with_amount_min_20_constraint:
code: 'tpay_pbl_one_channel_with_amount_min_20_constraint'
enabled: true
gatewayConfig: '@gateway_tpay_pbl_one_channel_with_amount_min_20_constraint'
translations:
- '@tpay_pbl_one_channel_with_amount_min_20_constraint_payment_method_translation'
channels: [ '@channel_web' ]
tpay_pbl_one_channel_with_amount_min_30_constraint:
code: 'tpay_pbl_one_channel_with_amount_min_30_constraint'
enabled: true
gatewayConfig: '@gateway_tpay_pbl_one_channel_with_amount_min_30_constraint'
translations:
- '@tpay_pbl_one_channel_with_amount_min_30_constraint_payment_method_translation'
channels: [ '@channel_web' ]
tpay_visa_mobile:
code: 'tpay_visa_mobile'
enabled: true
Expand Down Expand Up @@ -101,6 +115,26 @@ Sylius\Bundle\PayumBundle\Model\GatewayConfig:
type: 'pay_by_link'
production_mode: false
encrypted: true
gateway_tpay_pbl_one_channel_with_amount_min_20_constraint:
gatewayName: 'tpay_pbl'
factoryName: 'tpay_pbl'
config:
client_id: 'encrypted_<getenv("TPAY_CLIENT_ID")>'
client_secret: 'encrypted_<getenv("TPAY_CLIENT_SECRET")>'
tpay_channel_id: '4'
type: 'pay_by_link'
production_mode: false
encrypted: true
gateway_tpay_pbl_one_channel_with_amount_min_30_constraint:
gatewayName: 'tpay_pbl'
factoryName: 'tpay_pbl'
config:
client_id: 'encrypted_<getenv("TPAY_CLIENT_ID")>'
client_secret: 'encrypted_<getenv("TPAY_CLIENT_SECRET")>'
tpay_channel_id: '5'
type: 'pay_by_link'
production_mode: false
encrypted: true
gateway_tpay_visa_mobile:
gatewayName: 'tpay_visa_mobile'
factoryName: 'tpay_visa_mobile'
Expand Down Expand Up @@ -141,6 +175,16 @@ Sylius\Component\Payment\Model\PaymentMethodTranslation:
locale: 'en_US'
description: '<paragraph(2)>'
translatable: '@tpay_pbl_one_channel'
tpay_pbl_one_channel_with_amount_min_20_constraint_payment_method_translation:
name: 'One Bank With Amount Min 20 Constraint (Tpay)'
locale: 'en_US'
description: '<paragraph(2)>'
translatable: '@tpay_pbl_one_channel_with_amount_min_20_constraint'
tpay_pbl_one_channel_with_amount_min_30_constraint_payment_method_translation:
name: 'One Bank With Amount Min 30 Constraint (Tpay)'
locale: 'en_US'
description: '<paragraph(2)>'
translatable: '@tpay_pbl_one_channel_with_amount_min_20_constraint'
tpay_visa_mobile_payment_method_translation:
name: 'Visa mobile (Tpay)'
locale: 'en_US'
Expand Down
9 changes: 9 additions & 0 deletions tests/E2E/Shop/Checkout/TpayPayByLinkCheckoutTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,13 @@ public function test_it_completes_the_checkout_using_pay_by_link_channel_presele

$this->assertPageTitleContains('Thank you!');
}

public function test_it_cannot_complete_the_checkout_using_not_supported_pay_by_link(): void
{
$element = $this->client->findElement(WebDriverBy::xpath('//*[@id="sylius-payment-methods"]/form/div[1]/div/div[2]'));

$this->assertStringContainsString('One Bank (Tpay)', $element->getText());
$this->assertStringContainsString('One Bank With Amount Min 20 Constraint (Tpay)', $element->getText());
$this->assertStringNotContainsString('One Bank With Amount Min 30 Constraint (Tpay)', $element->getText());
}
}
Loading

0 comments on commit 88c81b8

Please sign in to comment.