From c88edefcf645c61ed29fdaab64fbe71b560151a7 Mon Sep 17 00:00:00 2001 From: Kevin Kaniaburka Date: Fri, 8 Nov 2024 09:07:55 +0100 Subject: [PATCH] Resolve tpay transaction channels into an array if an error occurred --- config/services/payum/factory.php | 6 + config/services/tpay.php | 3 + .../GetTpayTransactionsChannelsFactory.php | 16 ++ ...ayTransactionsChannelsFactoryInterface.php | 12 ++ .../CachedTpayTransactionChannelResolver.php | 7 +- .../TpayTransactionChannelResolver.php | 35 ++++- .../config/packages/dev/monolog.yaml | 5 + .../TpayTransactionChannelResolverTest.php | 144 ++++++++++++++++++ 8 files changed, 219 insertions(+), 9 deletions(-) create mode 100644 src/Payum/Factory/GetTpayTransactionsChannelsFactory.php create mode 100644 src/Payum/Factory/GetTpayTransactionsChannelsFactoryInterface.php create mode 100644 tests/Unit/Tpay/Resolver/TpayTransactionChannelResolverTest.php diff --git a/config/services/payum/factory.php b/config/services/payum/factory.php index 0466c94e..472947e2 100644 --- a/config/services/payum/factory.php +++ b/config/services/payum/factory.php @@ -6,6 +6,8 @@ use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\CreateTransactionFactory; use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\CreateTransactionFactoryInterface; +use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\GetTpayTransactionsChannelsFactory; +use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\GetTpayTransactionsChannelsFactoryInterface; use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\InitializeApplePayPaymentFactory; use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\InitializeApplePayPaymentFactoryInterface; use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\NotifyDataFactory; @@ -35,6 +37,10 @@ ->alias(CreateTransactionFactoryInterface::class, 'commerce_weavers_sylius_tpay.payum.factory.create_transaction') ; + $services->set('commerce_weavers_sylius_tpay.payum.factory.get_tpay_transactions_channels', GetTpayTransactionsChannelsFactory::class) + ->alias(GetTpayTransactionsChannelsFactoryInterface::class, 'commerce_weavers_sylius_tpay.payum.factory.get_tpay_transactions_channels') + ; + $services->set('commerce_weavers_sylius_tpay.payum.factory.initialize_apple_pay_payment', InitializeApplePayPaymentFactory::class) ->alias(InitializeApplePayPaymentFactoryInterface::class, 'commerce_weavers_sylius_tpay.payum.factory.initialize_apple_pay_payment') ; diff --git a/config/services/tpay.php b/config/services/tpay.php index d12b501e..6d75789a 100644 --- a/config/services/tpay.php +++ b/config/services/tpay.php @@ -178,7 +178,10 @@ $services->set('commerce_weavers_sylius_tpay.tpay.resolver.tpay_transaction_channel_resolver', TpayTransactionChannelResolver::class) ->args([ service('payum'), + service('commerce_weavers_sylius_tpay.payum.factory.get_tpay_transactions_channels'), + service('logger')->nullOnInvalid(), ]) + ->tag('monolog.logger', ['channel' => 'sylius_tpay']) ->alias(AvailableTpayChannelListProviderInterface::class, 'commerce_weavers_sylius_tpay.tpay.resolver.tpay_transaction_channel_resolver') ; diff --git a/src/Payum/Factory/GetTpayTransactionsChannelsFactory.php b/src/Payum/Factory/GetTpayTransactionsChannelsFactory.php new file mode 100644 index 00000000..18682488 --- /dev/null +++ b/src/Payum/Factory/GetTpayTransactionsChannelsFactory.php @@ -0,0 +1,16 @@ +cache->get(self::COMMERCE_WEAVERS_SYLIUS_TPAY_TRANSACTION_CHANNELS, function (ItemInterface $item): array { + return (array) $this->cache->get(self::COMMERCE_WEAVERS_SYLIUS_TPAY_TRANSACTION_CHANNELS, function (ItemInterface $item): array { $item->expiresAfter($this->cacheTtlInSeconds); return $this->decorated->resolve(); }); - - Assert::isArray($result); - - return $result; } } diff --git a/src/Tpay/Resolver/TpayTransactionChannelResolver.php b/src/Tpay/Resolver/TpayTransactionChannelResolver.php index 7a61051c..0116773f 100644 --- a/src/Tpay/Resolver/TpayTransactionChannelResolver.php +++ b/src/Tpay/Resolver/TpayTransactionChannelResolver.php @@ -4,28 +4,57 @@ namespace CommerceWeavers\SyliusTpayPlugin\Tpay\Resolver; -use CommerceWeavers\SyliusTpayPlugin\Payum\Exception\UnableToGetBankListException; +use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\GetTpayTransactionsChannelsFactoryInterface; use CommerceWeavers\SyliusTpayPlugin\Payum\Request\Api\GetTpayTransactionsChannels; use Payum\Core\Model\ArrayObject; use Payum\Core\Payum; +use Psr\Log\LoggerInterface; +use Tpay\OpenApi\Utilities\TpayException; final class TpayTransactionChannelResolver implements TpayTransactionChannelResolverInterface { public function __construct( private readonly Payum $payum, + private readonly ?GetTpayTransactionsChannelsFactoryInterface $getTpayTransactionsChannelsFactory = null, + private readonly ?LoggerInterface $logger = null, ) { + if (null === $this->getTpayTransactionsChannelsFactory) { + trigger_deprecation( + 'commerce-weavers/sylius-tpay-plugin', + '1.0', + 'Not passing a $getTpayTransactionsChannelsFactory to %s constructor is deprecated and will be removed in SyliusTpayPlugin 2.0.', + self::class, + ); + } } public function resolve(): array { $gateway = $this->payum->getGateway('tpay'); - $gateway->execute($value = new GetTpayTransactionsChannels(new ArrayObject()), true); + $value = $this->getTpayTransactionsChannelsFactory?->createNewEmpty() + ?? new GetTpayTransactionsChannels(new ArrayObject()); + + try { + $gateway->execute($value, true); + } catch (TpayException $e) { + $this->logger?->critical('Unable to get banks list. TpayException thrown.', ['exceptionMessage' => $e->getMessage()]); + + return []; + } $result = $value->getResult(); if (!isset($result['result']) || 'success' !== $result['result']) { - throw new UnableToGetBankListException('Unable to get banks list. Response: ' . json_encode($result)); + $this->logger?->critical('Unable to get banks list. The result is not success.', ['responseBody' => json_encode($result)]); + + return []; + } + + if (!isset($result['channels'])) { + $this->logger?->critical('Unable to get banks list. The channels key is missing.', ['responseBody' => json_encode($result)]); + + return []; } $indexedResult = []; diff --git a/tests/Application/config/packages/dev/monolog.yaml b/tests/Application/config/packages/dev/monolog.yaml index da2b092d..d948d7b2 100644 --- a/tests/Application/config/packages/dev/monolog.yaml +++ b/tests/Application/config/packages/dev/monolog.yaml @@ -7,3 +7,8 @@ monolog: firephp: type: firephp level: info + sylius_tpay: + type: stream + path: "%kernel.logs_dir%/sylius_tpay_%kernel.environment%.log" + level: debug + channels: [sylius_tpay] diff --git a/tests/Unit/Tpay/Resolver/TpayTransactionChannelResolverTest.php b/tests/Unit/Tpay/Resolver/TpayTransactionChannelResolverTest.php new file mode 100644 index 00000000..12e9aeaf --- /dev/null +++ b/tests/Unit/Tpay/Resolver/TpayTransactionChannelResolverTest.php @@ -0,0 +1,144 @@ +payum = $this->prophesize(Payum::class); + $this->getTpayTransactionsChannelsFactory = $this->prophesize(GetTpayTransactionsChannelsFactoryInterface::class); + $this->logger = $this->prophesize(LoggerInterface::class); + } + + public function test_it_resolves_tpay_transaction_channels(): void + { + $gateway = $this->prophesize(GatewayInterface::class); + $value = $this->prophesize(GetTpayTransactionsChannels::class); + $this->payum->getGateway('tpay')->willReturn($gateway); + $this->getTpayTransactionsChannelsFactory->createNewEmpty()->willReturn($value); + $gateway->execute($value, true)->shouldBeCalled(); + $value->getResult()->willReturn([ + 'result' => 'success', + 'channels' => [ + ['id' => 1, 'name' => 'Bank 1'], + ['id' => 2, 'name' => 'Bank 2'], + ], + ]); + + $result = $this->createTestSubject()->resolve(); + + $this->assertEquals([ + 1 => ['id' => 1, 'name' => 'Bank 1'], + 2 => ['id' => 2, 'name' => 'Bank 2'], + ], $result); + } + + public function test_it_resolves_an_empty_array_when_tpay_exception_is_thrown(): void + { + $gateway = $this->prophesize(GatewayInterface::class); + $value = $this->prophesize(GetTpayTransactionsChannels::class); + $this->payum->getGateway('tpay')->willReturn($gateway); + $this->getTpayTransactionsChannelsFactory->createNewEmpty()->willReturn($value); + $gateway + ->execute($value, true) + ->willThrow(new TpayException('Booo! I am a TpayException!')) + ; + $this->logger + ->critical('Unable to get banks list. TpayException thrown.', Argument::withKey('exceptionMessage')) + ->shouldBeCalled() + ; + + $result = $this->createTestSubject()->resolve(); + + $this->assertEquals([], $result); + } + + public function test_it_resolves_an_empty_array_when_the_result_is_not_success(): void + { + $gateway = $this->prophesize(GatewayInterface::class); + $value = $this->prophesize(GetTpayTransactionsChannels::class); + $this->payum->getGateway('tpay')->willReturn($gateway); + $value->getResult()->willReturn(['result' => 'failure']); + $this->getTpayTransactionsChannelsFactory->createNewEmpty()->willReturn($value); + $gateway->execute($value, true)->shouldBeCalled(); + + $this->logger + ->critical('Unable to get banks list. The result is not success.', ['responseBody' => '{"result":"failure"}']) + ->shouldBeCalled() + ; + + $result = $this->createTestSubject()->resolve(); + + $this->assertEquals([], $result); + } + + public function test_it_resolves_an_empty_array_when_the_channels_key_is_missing(): void + { + $gateway = $this->prophesize(GatewayInterface::class); + $value = $this->prophesize(GetTpayTransactionsChannels::class); + $this->payum->getGateway('tpay')->willReturn($gateway); + $value->getResult()->willReturn(['result' => 'success']); + $this->getTpayTransactionsChannelsFactory->createNewEmpty()->willReturn($value); + $gateway->execute($value, true)->shouldBeCalled(); + + $this->logger + ->critical('Unable to get banks list. The channels key is missing.', ['responseBody' => '{"result":"success"}']) + ->shouldBeCalled() + ; + + $result = $this->createTestSubject()->resolve(); + + $this->assertEquals([], $result); + } + + public function test_it_does_not_log_errors_if_logger_is_null(): void + { + $gateway = $this->prophesize(GatewayInterface::class); + $value = $this->prophesize(GetTpayTransactionsChannels::class); + $this->payum->getGateway('tpay')->willReturn($gateway); + $value->getResult()->willReturn(['result' => 'failure']); + $this->getTpayTransactionsChannelsFactory->createNewEmpty()->willReturn($value); + $gateway->execute($value, true)->shouldBeCalled(); + + $this->logger->critical(Argument::cetera())->shouldNotBeCalled(); + + $result = $this->createTestSubject(false)->resolve(); + + $this->assertEquals([], $result); + } + + private function createTestSubject(bool $withLogger = true): TpayTransactionChannelResolver + { + return new TpayTransactionChannelResolver( + $this->payum->reveal(), + $this->getTpayTransactionsChannelsFactory->reveal(), + $withLogger ? $this->logger->reveal() : null, + ); + } +}