From 9c730a2924a02066c784ae4a717994e497907b6e Mon Sep 17 00:00:00 2001 From: Kevin Kaniaburka Date: Tue, 10 Dec 2024 18:37:33 +0100 Subject: [PATCH 1/4] Add OrderAwareValidTpayChannelListProvider --- config/services/tpay.php | 9 ++ ...OrderAwareValidTpayChannelListProvider.php | 43 +++++++ ...eValidTpayChannelListProviderInterface.php | 12 ++ ...rAwareValidTpayChannelListProviderTest.php | 121 ++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php create mode 100644 src/Tpay/Provider/OrderAwareValidTpayChannelListProviderInterface.php create mode 100644 tests/Unit/Tpay/Provider/OrderAwareValidTpayChannelListProviderTest.php diff --git a/config/services/tpay.php b/config/services/tpay.php index 5629a01b..480d0c34 100644 --- a/config/services/tpay.php +++ b/config/services/tpay.php @@ -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; @@ -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'), diff --git a/src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php b/src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php new file mode 100644 index 00000000..e8e529bc --- /dev/null +++ b/src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php @@ -0,0 +1,43 @@ +getTotal(); + $channelList = $this->validTpayChannelListProvider->provide(); + + foreach ($channelList as $key => $channel) { + foreach ($channel['constraints'] ?? [] as $constraint) { + if ('amount' !== $constraint['field']) { + continue; + } + + $constraintValue = (int) $constraint['value'] * self::FLOAT_AMOUNT_VALUE_TO_INT_MULTIPLIER; + + if ( + ('min' === $constraint['type'] && $orderTotal < $constraintValue) || + ('max' === $constraint['type'] && $orderTotal > $constraintValue) + ) { + unset($channelList[$key]); + + break; + } + } + } + + return $channelList; + } +} diff --git a/src/Tpay/Provider/OrderAwareValidTpayChannelListProviderInterface.php b/src/Tpay/Provider/OrderAwareValidTpayChannelListProviderInterface.php new file mode 100644 index 00000000..6c1b6906 --- /dev/null +++ b/src/Tpay/Provider/OrderAwareValidTpayChannelListProviderInterface.php @@ -0,0 +1,12 @@ + [ + 'id' => '1', + 'name' => 'some bank', + 'available' => true, + 'groups' => [ + ['id' => '1'], + ], + ], + '2' => [ + 'id' => '2', + 'name' => 'BLIK', + 'available' => true, + 'groups' => [ + ['id' => '150'], + ], + ], + '3' => [ + 'id' => '3', + 'name' => 'PayPo', + 'available' => true, + 'groups' => [ + ['id' => '169'], + ], + 'constraints' => [ + [ + 'field' => 'amount', + 'type' => 'min', + 'value' => '30.00', + ], + ], + ], + '4' => [ + 'id' => '4', + 'name' => 'PayPo', + 'available' => true, + 'groups' => [ + ['id' => '172'], + ], + 'constraints' => [ + [ + 'field' => 'amount', + 'type' => 'max', + 'value' => '4000.00', + ], + ], + ], + '5' => [ + 'id' => '5', + 'name' => 'BLIK Płacę Później', + 'available' => true, + 'groups' => [ + ['id' => '173'], + ], + 'constraints' => [ + [ + 'field' => 'amount', + 'type' => 'min', + 'value' => '30.00', + ], + [ + 'field' => 'amount', + 'type' => 'max', + 'value' => '4000.00', + ], + ], + ], + ]; + + /** + * @dataProvider orderTotalDataProvider + */ + public function test_it_provides_valid_tpay_channels_for_order(int $orderTotal, array $expectedChannels): void + { + $validTpayChannelListProvider = $this->prophesize(ValidTpayChannelListProviderInterface::class); + $order = $this->prophesize(OrderInterface::class); + $validTpayChannelListProvider->provide()->willReturn(self::BANK_LIST); + $order->getTotal()->willReturn($orderTotal); + + $result = (new OrderAwareValidTpayChannelListProvider( + $validTpayChannelListProvider->reveal(), + ))->provide($order->reveal()); + + $this->assertSame($expectedChannels, array_keys($result)); + } + + private function orderTotalDataProvider(): array + { + return [ + [ + 'orderTotal' => 3000_00, + 'expectedChannels' => [1, 2, 3, 4, 5], + ], + [ + 'orderTotal' => 10_00, + 'expectedChannels' => [1, 2, 4], + ], + [ + 'orderTotal' => 5000_00, + 'expectedChannels' => [1, 2, 3], + ], + ]; + } +} From b30253615fe064261d42656fe3596d823ac8d8a7 Mon Sep 17 00:00:00 2001 From: Kevin Kaniaburka Date: Tue, 10 Dec 2024 19:37:12 +0100 Subject: [PATCH 2/4] Use OrderAwareValidTpayChannelListProvider in BankListContextProvider --- .../pay_by_link_payment/context_provider.php | 1 + .../ContextProvider/BankListContextProvider.php | 13 ++++++++++++- .../ContextProvider/BankListContextProviderTest.php | 11 ++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/config/services/pay_by_link_payment/context_provider.php b/config/services/pay_by_link_payment/context_provider.php index a57a6fa7..d6653186 100644 --- a/config/services/pay_by_link_payment/context_provider.php +++ b/config/services/pay_by_link_payment/context_provider.php @@ -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') diff --git a/src/PayByLinkPayment/ContextProvider/BankListContextProvider.php b/src/PayByLinkPayment/ContextProvider/BankListContextProvider.php index d629b09b..b5595385 100644 --- a/src/PayByLinkPayment/ContextProvider/BankListContextProvider.php +++ b/src/PayByLinkPayment/ContextProvider/BankListContextProvider.php @@ -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; @@ -23,6 +24,7 @@ final class BankListContextProvider implements ContextProviderInterface public function __construct( private readonly ValidTpayChannelListProviderInterface $validTpayChannelListProvider, + private readonly OrderAwareValidTpayChannelListProviderInterface $orderAwareValidTpayChannelListProvider, private readonly CypherInterface $cypher, ) { } @@ -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; } diff --git a/tests/Unit/PayByLinkPayment/ContextProvider/BankListContextProviderTest.php b/tests/Unit/PayByLinkPayment/ContextProvider/BankListContextProviderTest.php index 156bd32f..e215d83a 100644 --- a/tests/Unit/PayByLinkPayment/ContextProvider/BankListContextProviderTest.php +++ b/tests/Unit/PayByLinkPayment/ContextProvider/BankListContextProviderTest.php @@ -6,9 +6,11 @@ use CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\ContextProvider\BankListContextProvider; use CommerceWeavers\SyliusTpayPlugin\PayByLinkPayment\Payum\Factory\GatewayFactory as PayByLinkGatewayFactory; +use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\OrderAwareValidTpayChannelListProviderInterface; use CommerceWeavers\SyliusTpayPlugin\Tpay\Provider\ValidTpayChannelListProviderInterface; use Payum\Core\Security\CypherInterface; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; use Sylius\Bundle\PayumBundle\Model\GatewayConfig; @@ -23,11 +25,14 @@ class BankListContextProviderTest extends TestCase private ValidTpayChannelListProviderInterface|ObjectProphecy $validTpayChannelListProvider; + private OrderAwareValidTpayChannelListProviderInterface|ObjectProphecy $orderAwareValidTpayChannelListProvider; + private CypherInterface|ObjectProphecy $cypher; protected function setUp(): void { $this->validTpayChannelListProvider = $this->prophesize(ValidTpayChannelListProviderInterface::class); + $this->orderAwareValidTpayChannelListProvider = $this->prophesize(OrderAwareValidTpayChannelListProviderInterface::class); $this->cypher = $this->prophesize(CypherInterface::class); } @@ -65,6 +70,7 @@ public function test_it_provides_banks_in_template_context_if_method_is_present_ $paymentMethod->getGatewayConfig()->willReturn($gatewayConfig); $gatewayConfig->getFactoryName()->willReturn(PayByLinkGatewayFactory::NAME); $gatewayConfig->getConfig()->willReturn([]); + $this->orderAwareValidTpayChannelListProvider->provide(Argument::any())->shouldNotBeCalled(); $this->validTpayChannelListProvider->provide()->willReturn(['3' => 'somebank']); $result = $this @@ -97,7 +103,8 @@ public function test_it_provides_banks_in_template_context_if_order_is_present_i $paymentMethod->getGatewayConfig()->willReturn($gatewayConfig); $gatewayConfig->getFactoryName()->willReturn(PayByLinkGatewayFactory::NAME); $gatewayConfig->getConfig()->willReturn([]); - $this->validTpayChannelListProvider->provide()->willReturn(['3' => 'somebank']); + $this->validTpayChannelListProvider->provide()->shouldNotBeCalled(); + $this->orderAwareValidTpayChannelListProvider->provide($order)->willReturn(['3' => 'somebank']); $result = $this ->createTestObject() @@ -203,6 +210,7 @@ public function test_it_provides_channel_id_and_empty_banks_in_template_context_ $gatewayConfig->decrypt($this->cypher)->shouldBeCalled(); $this->validTpayChannelListProvider->provide()->shouldNotBeCalled(); + $this->orderAwareValidTpayChannelListProvider->provide(Argument::any())->shouldNotBeCalled(); $this->assertSame( [ 'method' => $paymentMethod->reveal(), @@ -217,6 +225,7 @@ private function createTestObject(): BankListContextProvider { return new BankListContextProvider( $this->validTpayChannelListProvider->reveal(), + $this->orderAwareValidTpayChannelListProvider->reveal(), $this->cypher->reveal(), ); } From 8ad8c23e13709e41f7afe949854edf6c50f9b86b Mon Sep 17 00:00:00 2001 From: Kevin Kaniaburka Date: Wed, 11 Dec 2024 12:06:56 +0100 Subject: [PATCH 3/4] Add OrderBasedPaymentMethodsResolver --- .../services/pay_by_link_payment/checker.php | 20 +++ config/services/payment.php | 9 ++ .../PaymentMethodSupportedForOrderChecker.php | 46 ++++++ ...ethodSupportedForOrderCheckerInterface.php | 13 ++ .../OrderBasedPaymentMethodsResolver.php | 48 +++++++ .../fixtures/common/payment_method.yaml | 44 ++++++ .../Checkout/TpayPayByLinkCheckoutTest.php | 9 ++ ...mentMethodSupportedForOrderCheckerTest.php | 124 +++++++++++++++++ .../OrderBasedPaymentMethodsResolverTest.php | 131 ++++++++++++++++++ tests/mockoon_tpay.json | 2 +- 10 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 config/services/pay_by_link_payment/checker.php create mode 100644 src/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderChecker.php create mode 100644 src/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderCheckerInterface.php create mode 100644 src/Payment/Resolver/OrderBasedPaymentMethodsResolver.php create mode 100644 tests/Unit/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderCheckerTest.php create mode 100644 tests/Unit/Payment/Resolver/OrderBasedPaymentMethodsResolverTest.php diff --git a/config/services/pay_by_link_payment/checker.php b/config/services/pay_by_link_payment/checker.php new file mode 100644 index 00000000..eb561ff4 --- /dev/null +++ b/config/services/pay_by_link_payment/checker.php @@ -0,0 +1,20 @@ +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') + ; +}; diff --git a/config/services/payment.php b/config/services/payment.php index 942336f7..be59413c 100644 --- a/config/services/payment.php +++ b/config/services/payment.php @@ -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(); @@ -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]) + ; }; diff --git a/src/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderChecker.php b/src/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderChecker.php new file mode 100644 index 00000000..f4eff174 --- /dev/null +++ b/src/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderChecker.php @@ -0,0 +1,46 @@ +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]); + } +} diff --git a/src/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderCheckerInterface.php b/src/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderCheckerInterface.php new file mode 100644 index 00000000..151a9bfa --- /dev/null +++ b/src/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderCheckerInterface.php @@ -0,0 +1,13 @@ +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); + } +} diff --git a/tests/E2E/Resources/fixtures/common/payment_method.yaml b/tests/E2E/Resources/fixtures/common/payment_method.yaml index a2851b8b..8a9886e0 100644 --- a/tests/E2E/Resources/fixtures/common/payment_method.yaml +++ b/tests/E2E/Resources/fixtures/common/payment_method.yaml @@ -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 @@ -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_' + client_secret: 'encrypted_' + 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_' + client_secret: 'encrypted_' + 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' @@ -141,6 +175,16 @@ Sylius\Component\Payment\Model\PaymentMethodTranslation: locale: 'en_US' description: '' 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: '' + 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: '' + translatable: '@tpay_pbl_one_channel_with_amount_min_20_constraint' tpay_visa_mobile_payment_method_translation: name: 'Visa mobile (Tpay)' locale: 'en_US' diff --git a/tests/E2E/Shop/Checkout/TpayPayByLinkCheckoutTest.php b/tests/E2E/Shop/Checkout/TpayPayByLinkCheckoutTest.php index 27cd7773..625d2a60 100644 --- a/tests/E2E/Shop/Checkout/TpayPayByLinkCheckoutTest.php +++ b/tests/E2E/Shop/Checkout/TpayPayByLinkCheckoutTest.php @@ -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()); + } } diff --git a/tests/Unit/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderCheckerTest.php b/tests/Unit/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderCheckerTest.php new file mode 100644 index 00000000..aefcf16a --- /dev/null +++ b/tests/Unit/PayByLinkPayment/Checker/PaymentMethodSupportedForOrderCheckerTest.php @@ -0,0 +1,124 @@ +cypher = $this->prophesize(CypherInterface::class); + $this->orderAwareValidTpayChannelListProvider = $this->prophesize(OrderAwareValidTpayChannelListProviderInterface::class); + $this->paymentMethod = $this->prophesize(PaymentMethodInterface::class); + $this->order = $this->prophesize(OrderInterface::class); + } + + public function test_it_returns_true_if_gateway_config_is_null(): void + { + $this->paymentMethod->getGatewayConfig()->willReturn(null); + + $result = $this + ->createTestSubject() + ->isSupportedForOrder($this->paymentMethod->reveal(), $this->order->reveal()) + ; + + $this->assertTrue($result); + } + + public function test_it_returns_true_if_gateway_config_factory_name_is_not_pay_by_link(): void + { + $gatewayConfig = $this->prophesize(GatewayConfigInterface::class); + $this->paymentMethod->getGatewayConfig()->willReturn($gatewayConfig->reveal()); + $gatewayConfig->getFactoryName()->willReturn('i_am_not_pay_by_link'); + + $result = $this + ->createTestSubject() + ->isSupportedForOrder($this->paymentMethod->reveal(), $this->order->reveal()) + ; + + $this->assertTrue($result); + } + + public function test_it_returns_true_if_gateway_config_does_not_have_tpay_channel_id(): void + { + $gatewayConfig = $this->prophesize(GatewayConfigInterface::class); + $this->paymentMethod->getGatewayConfig()->willReturn($gatewayConfig->reveal()); + $gatewayConfig->getFactoryName()->willReturn(GatewayName::PAY_BY_LINK); + $gatewayConfig->getConfig()->willReturn([]); + + $result = $this + ->createTestSubject() + ->isSupportedForOrder($this->paymentMethod->reveal(), $this->order->reveal()) + ; + + $this->assertTrue($result); + } + + public function test_it_returns_true_if_tpay_channel_id_is_valid(): void + { + $gatewayConfig = $this->prophesize(GatewayConfigInterface::class); + $this->paymentMethod->getGatewayConfig()->willReturn($gatewayConfig); + $gatewayConfig->getFactoryName()->willReturn(GatewayName::PAY_BY_LINK); + $gatewayConfig->getConfig()->willReturn(['tpay_channel_id' => 21]); + $this->orderAwareValidTpayChannelListProvider + ->provide($this->order) + ->willReturn([19 => [], 21 => [], 22 => []]) + ; + + $result = $this + ->createTestSubject() + ->isSupportedForOrder($this->paymentMethod->reveal(), $this->order->reveal()) + ; + + $this->assertTrue($result); + } + + public function test_it_returns_false_if_tpay_channel_id_is_not_valid(): void + { + $gatewayConfig = $this->prophesize(GatewayConfigInterface::class); + $this->paymentMethod->getGatewayConfig()->willReturn($gatewayConfig->reveal()); + $gatewayConfig->getFactoryName()->willReturn(GatewayName::PAY_BY_LINK); + $gatewayConfig->getConfig()->willReturn(['tpay_channel_id' => 21]); + $this->orderAwareValidTpayChannelListProvider + ->provide($this->order) + ->willReturn([19 => [], 22 => []]) + ; + + $result = $this + ->createTestSubject() + ->isSupportedForOrder($this->paymentMethod->reveal(), $this->order->reveal()) + ; + + $this->assertFalse($result); + } + + private function createTestSubject(): PaymentMethodSupportedForOrderChecker + { + return new PaymentMethodSupportedForOrderChecker( + $this->cypher->reveal(), + $this->orderAwareValidTpayChannelListProvider->reveal(), + ); + } +} diff --git a/tests/Unit/Payment/Resolver/OrderBasedPaymentMethodsResolverTest.php b/tests/Unit/Payment/Resolver/OrderBasedPaymentMethodsResolverTest.php new file mode 100644 index 00000000..e8f9b2ef --- /dev/null +++ b/tests/Unit/Payment/Resolver/OrderBasedPaymentMethodsResolverTest.php @@ -0,0 +1,131 @@ +paymentMethodResolver = $this->prophesize(PaymentMethodsResolverInterface::class); + $this->paymentMethodSupportedForOrderChecker = $this->prophesize(PaymentMethodSupportedForOrderCheckerInterface::class); + $this->subject = $this->prophesize(CorePaymentInterface::class); + } + + public function test_it_gets_order_based_supported_methods(): void + { + $firstPaymentMethod = $this->prophesize(PaymentMethodInterface::class); + $secondPaymentMethod = $this->prophesize(PaymentMethodInterface::class); + $thirdPaymentMethod = $this->prophesize(PaymentMethodInterface::class); + $order = $this->prophesize(OrderInterface::class); + $this->paymentMethodResolver + ->getSupportedMethods($this->subject) + ->willReturn([ + $firstPaymentMethod->reveal(), + $secondPaymentMethod->reveal(), + $thirdPaymentMethod->reveal(), + ]) + ; + $this->paymentMethodResolver->supports($this->subject)->willReturn(true); + $this->subject->getOrder()->willReturn($order); + $this->paymentMethodSupportedForOrderChecker + ->isSupportedForOrder($firstPaymentMethod, $order) + ->willReturn(true) + ; + $this->paymentMethodSupportedForOrderChecker + ->isSupportedForOrder($secondPaymentMethod, $order) + ->willReturn(false) + ; + $this->paymentMethodSupportedForOrderChecker + ->isSupportedForOrder($thirdPaymentMethod, $order) + ->willReturn(true) + ; + + $result = $this + ->createTestSubject() + ->getSupportedMethods($this->subject->reveal()) + ; + + $this->assertCount(2, $result); + $this->assertSame($firstPaymentMethod->reveal(), $result[0]); + $this->assertSame($thirdPaymentMethod->reveal(), $result[1]); + } + + public function test_it_throws_exception_if_subject_order_is_null(): void + { + $firstPaymentMethod = $this->prophesize(PaymentMethodInterface::class); + $secondPaymentMethod = $this->prophesize(PaymentMethodInterface::class); + $thirdPaymentMethod = $this->prophesize(PaymentMethodInterface::class); + $this->paymentMethodResolver + ->getSupportedMethods($this->subject) + ->willReturn([ + $firstPaymentMethod->reveal(), + $secondPaymentMethod->reveal(), + $thirdPaymentMethod->reveal(), + ]) + ; + $this->paymentMethodResolver->supports($this->subject)->willReturn(true); + $this->subject->getOrder()->willReturn(null); + + $this->expectException(InvalidArgumentException::class); + + $this + ->createTestSubject() + ->getSupportedMethods($this->subject->reveal()) + ; + } + + public function test_it_throws_exception_if_resolver_is_not_supported(): void + { + $this->paymentMethodResolver->supports($this->subject)->willReturn(false); + + $this->expectException(InvalidArgumentException::class); + + $this + ->createTestSubject() + ->getSupportedMethods($this->subject->reveal()) + ; + } + + public function test_it_throws_exception_if_subject_is_not_core_payment(): void + { + $subject = $this->prophesize(PaymentInterface::class); + + $this->expectException(InvalidArgumentException::class); + + $this + ->createTestSubject() + ->getSupportedMethods($subject->reveal()) + ; + } + + private function createTestSubject(): OrderBasedPaymentMethodsResolver + { + return new OrderBasedPaymentMethodsResolver( + $this->paymentMethodResolver->reveal(), + $this->paymentMethodSupportedForOrderChecker->reveal() + ); + } +} diff --git a/tests/mockoon_tpay.json b/tests/mockoon_tpay.json index 6430147d..38ab3f04 100644 --- a/tests/mockoon_tpay.json +++ b/tests/mockoon_tpay.json @@ -732,7 +732,7 @@ "responses": [ { "uuid": "924f9fab-d6ab-4365-b84b-e8ab13514143", - "body": "{\n \"result\":\"success\",\n \"requestId\":\"c36e286ceb64a95b8858\",\n \"language\":\"pl\",\n \"currency\":\"PLN\",\n \"channels\":[\n {\n \"id\":\"1\",\n \"name\":\"BNP Paribas\",\n \"fullName\":\"BNP Paribas Bank Polska SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/1/normal-white-bg-e.png\"\n },\n \"available\":true,\n \"onlinePayment\":true,\n \"instantRedirection\":true,\n \"groups\":[\n {\n \"id\":\"133\",\n \"name\":\"BNP Paribas Bank Polska SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/133/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n \n ]\n },\n {\n \"id\":\"2\",\n \"name\":\"Not a bank\",\n \"fullName\":\"Not a bank\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/2/normal-white-bg-e.png\"\n },\n \"available\":true,\n \"onlinePayment\":true,\n \"instantRedirection\":false,\n \"groups\":[\n {\n \"id\":\"114\",\n \"name\":\"Bank Millennium SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/114/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n \n ]\n },\n {\n \"id\":\"3\",\n \"name\":\"Unavailable\",\n \"fullName\":\"Unavailable\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/4/normal-white-bg-e.png\"\n },\n \"available\":false,\n \"onlinePayment\":true,\n \"instantRedirection\":true,\n \"groups\":[\n {\n \"id\":\"102\",\n \"name\":\"Bank Pekao SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/102/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n \n ]\n },\n {\n \"id\":\"991\",\n \"name\":\"FAIL bank\",\n \"fullName\":\"FAIL bank SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/1/normal-white-bg-e.png\"\n },\n \"available\":true,\n \"onlinePayment\":true,\n \"instantRedirection\":true,\n \"groups\":[\n {\n \"id\":\"991\",\n \"name\":\"FAIL BANK\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/133/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n \n ]\n }\n ]\n}", + "body": "{\n \"result\":\"success\",\n \"requestId\":\"c36e286ceb64a95b8858\",\n \"language\":\"pl\",\n \"currency\":\"PLN\",\n \"channels\":[\n {\n \"id\":\"1\",\n \"name\":\"BNP Paribas\",\n \"fullName\":\"BNP Paribas Bank Polska SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/1/normal-white-bg-e.png\"\n },\n \"available\":true,\n \"onlinePayment\":true,\n \"instantRedirection\":true,\n \"groups\":[\n {\n \"id\":\"133\",\n \"name\":\"BNP Paribas Bank Polska SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/133/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n \n ]\n },\n {\n \"id\":\"2\",\n \"name\":\"Not a bank\",\n \"fullName\":\"Not a bank\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/2/normal-white-bg-e.png\"\n },\n \"available\":true,\n \"onlinePayment\":true,\n \"instantRedirection\":false,\n \"groups\":[\n {\n \"id\":\"114\",\n \"name\":\"Bank Millennium SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/114/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n \n ]\n },\n {\n \"id\":\"3\",\n \"name\":\"Unavailable\",\n \"fullName\":\"Unavailable\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/4/normal-white-bg-e.png\"\n },\n \"available\":false,\n \"onlinePayment\":true,\n \"instantRedirection\":true,\n \"groups\":[\n {\n \"id\":\"102\",\n \"name\":\"Bank Pekao SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/102/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n \n ]\n },\n {\n \"id\":\"4\",\n \"name\":\"Restricted 1\",\n \"fullName\":\"Restricted 1\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/5/normal-white-bg-e.png\"\n },\n \"available\":true,\n \"onlinePayment\":true,\n \"instantRedirection\":true,\n \"groups\":[\n {\n \"id\":\"102\",\n \"name\":\"Bank Pekao SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/102/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n {\n \"field\": \"amount\",\n \"type\": \"min\",\n \"value\": \"20.00\"\n },\n {\n \"field\": \"amount\",\n \"type\": \"max\",\n \"value\": \"20000.00\"\n }\n ]\n },\n {\n \"id\":\"5\",\n \"name\":\"Restricted 2\",\n \"fullName\":\"Restricted 2\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/5/normal-white-bg-e.png\"\n },\n \"available\":true,\n \"onlinePayment\":true,\n \"instantRedirection\":true,\n \"groups\":[\n {\n \"id\":\"102\",\n \"name\":\"Bank Pekao SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/102/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n {\n \"field\": \"amount\",\n \"type\": \"min\",\n \"value\": \"30.00\"\n },\n {\n \"field\": \"amount\",\n \"type\": \"max\",\n \"value\": \"20000.00\"\n }\n ]\n },\n {\n \"id\":\"991\",\n \"name\":\"FAIL bank\",\n \"fullName\":\"FAIL bank SA\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/channels/1/normal-white-bg-e.png\"\n },\n \"available\":true,\n \"onlinePayment\":true,\n \"instantRedirection\":true,\n \"groups\":[\n {\n \"id\":\"991\",\n \"name\":\"FAIL BANK\",\n \"image\":{\n \"url\":\"https://secure.sandbox.tpay.com/tpay/web/groups/133/normal-white-bg.png\"\n }\n }\n ],\n \"constraints\":[\n \n ]\n }\n ]\n}", "latency": 0, "statusCode": 200, "label": "", From 8d06567a01ffeda3801e82d885e21a844097eadc Mon Sep 17 00:00:00 2001 From: Kevin Kaniaburka Date: Wed, 11 Dec 2024 12:22:32 +0100 Subject: [PATCH 4/4] Fix OrderAwareValidTpayChannelListProvider in case of an invalid constraint --- ...OrderAwareValidTpayChannelListProvider.php | 12 ++-- ...rAwareValidTpayChannelListProviderTest.php | 57 +++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php b/src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php index e8e529bc..1e1b8f10 100644 --- a/src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php +++ b/src/Tpay/Provider/OrderAwareValidTpayChannelListProvider.php @@ -21,15 +21,19 @@ public function provide(OrderInterface $order): array foreach ($channelList as $key => $channel) { foreach ($channel['constraints'] ?? [] as $constraint) { - if ('amount' !== $constraint['field']) { + $constraintField = $constraint['field'] ?? null; + $constraintValue = $constraint['value'] ?? null; + $constraintType = $constraint['type'] ?? null; + + if ('amount' !== $constraintField || null == $constraintValue || null === $constraintType) { continue; } - $constraintValue = (int) $constraint['value'] * self::FLOAT_AMOUNT_VALUE_TO_INT_MULTIPLIER; + $constraintIntValue = (int) ($constraintValue * self::FLOAT_AMOUNT_VALUE_TO_INT_MULTIPLIER); if ( - ('min' === $constraint['type'] && $orderTotal < $constraintValue) || - ('max' === $constraint['type'] && $orderTotal > $constraintValue) + ('min' === $constraintType && $orderTotal < $constraintIntValue) || + ('max' === $constraintType && $orderTotal > $constraintIntValue) ) { unset($channelList[$key]); diff --git a/tests/Unit/Tpay/Provider/OrderAwareValidTpayChannelListProviderTest.php b/tests/Unit/Tpay/Provider/OrderAwareValidTpayChannelListProviderTest.php index 6b458dcb..79f17f97 100644 --- a/tests/Unit/Tpay/Provider/OrderAwareValidTpayChannelListProviderTest.php +++ b/tests/Unit/Tpay/Provider/OrderAwareValidTpayChannelListProviderTest.php @@ -101,6 +101,63 @@ public function test_it_provides_valid_tpay_channels_for_order(int $orderTotal, $this->assertSame($expectedChannels, array_keys($result)); } + public function test_it_does_not_validate_tpay_channels_if_constraints_exist_but_with_missing_fields(): void + { + $validTpayChannelListProvider = $this->prophesize(ValidTpayChannelListProviderInterface::class); + $order = $this->prophesize(OrderInterface::class); + $validTpayChannelListProvider->provide()->willReturn([ + '1' => [ + 'id' => '1', + 'name' => 'I am invalid because of missing field in constraint', + 'available' => true, + 'groups' => [ + ['id' => '173'], + ], + 'constraints' => [ + [ + 'type' => 'min', + 'value' => '30.00', + ] + ], + ], + '2' => [ + 'id' => '2', + 'name' => 'I am invalid because of missing type in constraint', + 'available' => true, + 'groups' => [ + ['id' => '173'], + ], + 'constraints' => [ + [ + 'field' => 'amount', + 'value' => '30.00', + ] + ], + ], + '3' => [ + 'id' => '3', + 'name' => 'I am invalid because of missing value in constraint', + 'available' => true, + 'groups' => [ + ['id' => '173'], + ], + 'constraints' => [ + [ + 'field' => 'amount', + 'type' => 'min', + ] + ], + ], + ]); + $order->getTotal()->willReturn(2000); + + $result = (new OrderAwareValidTpayChannelListProvider( + $validTpayChannelListProvider->reveal(), + ))->provide($order->reveal()); + + $this->assertSame([1, 2, 3], array_keys($result)); + } + private function orderTotalDataProvider(): array { return [