From 7e130edf5705cd9ba37314a535568635bbb23ce5 Mon Sep 17 00:00:00 2001 From: Luca Gallinari Date: Tue, 10 Sep 2024 11:39:49 +0200 Subject: [PATCH] Add payments method resolver for pausepay --- config/services/resolver.php | 9 + .../PausePayPaymentMethodsResolver.php | 103 ++++++++++++ .../PausePayPaymentMethodsResolverTest.php | 155 ++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 src/Resolver/PausePayPaymentMethodsResolver.php create mode 100644 tests/Unit/Resolver/PausePayPaymentMethodsResolverTest.php diff --git a/config/services/resolver.php b/config/services/resolver.php index 5f660fe..b58b755 100644 --- a/config/services/resolver.php +++ b/config/services/resolver.php @@ -5,9 +5,18 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Webgriffe\SyliusPausePayPlugin\Resolver\CompanyInfoResolver; +use Webgriffe\SyliusPausePayPlugin\Resolver\PausePayPaymentMethodsResolver; return static function (ContainerConfigurator $containerConfigurator) { $services = $containerConfigurator->services(); $services->set('webgriffe_sylius_pausepay.resolver.company_info', CompanyInfoResolver::class); + + $services->set('webgriffe_sylius_pausepay.resolver.payment_methods', PausePayPaymentMethodsResolver::class) + ->args([service('sylius.repository.payment_method'),]) + ->tag('sylius.payment_method_resolver', [ + 'type' => 'pausepay', + 'label' => 'PausePay', + 'priority' => 2, + ]); }; diff --git a/src/Resolver/PausePayPaymentMethodsResolver.php b/src/Resolver/PausePayPaymentMethodsResolver.php new file mode 100644 index 0000000..e1b960f --- /dev/null +++ b/src/Resolver/PausePayPaymentMethodsResolver.php @@ -0,0 +1,103 @@ +supports($subject), 'This payment method is not support by resolver'); + Assert::isInstanceOf($subject, PaymentInterface::class); + $order = $subject->getOrder(); + Assert::isInstanceOf($order, OrderInterface::class); + $channel = $order->getChannel(); + Assert::isInstanceOf($channel, ChannelInterface::class); + $billingAddress = $order->getBillingAddress(); + Assert::isInstanceOf($billingAddress, AddressInterface::class); + // todo: should we check the shipping address too? + $currencyCode = $order->getCurrencyCode(); + Assert::notNull($currencyCode); + $orderAmount = $order->getTotal(); + + /** @var PaymentMethodInterface[] $paymentMethods */ + $paymentMethods = $this->paymentMethodRepository->findEnabledForChannel($channel); + + return array_filter( + $paymentMethods, + static function (PaymentMethodInterface $paymentMethod) use ( + $billingAddress, + $currencyCode, + $orderAmount + ) { + $gatewayConfig = $paymentMethod->getGatewayConfig(); + if ($gatewayConfig === null) { + return false; + } + /** @psalm-suppress DeprecatedMethod */ + if ($gatewayConfig->getFactoryName() !== PausePayApi::GATEWAY_CODE) { + return true; + } + if ($billingAddress->getCountryCode() !== 'IT') { + return false; + } + if ($currencyCode !== 'EUR') { + return false; + } + if ($orderAmount < 50000 || $orderAmount > 2000000) { + return false; + } + + return true; + }, + ); + } + + public function supports(BasePaymentInterface $subject): bool + { + if (!$subject instanceof PaymentInterface) { + return false; + } + $order = $subject->getOrder(); + if (!$order instanceof OrderInterface) { + return false; + } + $channel = $order->getChannel(); + if (!$channel instanceof ChannelInterface) { + return false; + } + $paymentMethod = $subject->getMethod(); + if (!$paymentMethod instanceof PaymentMethodInterface) { + return false; + } + $billingAddress = $order->getBillingAddress(); + if (!$billingAddress instanceof AddressInterface) { + return false; + } + $currencyCode = $order->getCurrencyCode(); + + return $currencyCode !== null; + } +} diff --git a/tests/Unit/Resolver/PausePayPaymentMethodsResolverTest.php b/tests/Unit/Resolver/PausePayPaymentMethodsResolverTest.php new file mode 100644 index 0000000..de0a48e --- /dev/null +++ b/tests/Unit/Resolver/PausePayPaymentMethodsResolverTest.php @@ -0,0 +1,155 @@ +createMock(PaymentMethodRepositoryInterface::class); + $repoMock + ->method('findEnabledForChannel') + ->willReturn( + [ + $this->getPaymentMethod('paypal'), + $this->getPaymentMethod('credit_card'), + $this->getPaymentMethod(PausePayApi::GATEWAY_CODE), + ] + ); + $this->resolver = new PausePayPaymentMethodsResolver($repoMock); + } + + public function test_it_supports_payment(): void + { + self::assertTrue($this->resolver->supports($this->getPayment($this->getBaseOrder()))); + } + + public function test_it_resolves_payment_methods_by_returning_pausepay_and_all_others(): void + { + $supportedMethods = $this->resolver->getSupportedMethods($this->getPayment($this->getBaseOrder())); + + self::assertCount(3, $supportedMethods); + + self::assertSame($supportedMethods[0]->getCode(), 'paypal'); + self::assertSame($supportedMethods[1]->getCode(), 'credit_card'); + self::assertSame($supportedMethods[2]->getCode(), PausePayApi::GATEWAY_CODE); + } + + public function test_it_does_not_resolve_pausepay_with_non_italian_billing_address(): void + { + $order = $this->getBaseOrder(); + $order->getBillingAddress()->setCountryCode('FR'); + $supportedMethods = $this->resolver->getSupportedMethods($this->getPayment($order)); + + self::assertCount(2, $supportedMethods); + + self::assertSame($supportedMethods[0]->getCode(), 'paypal'); + self::assertSame($supportedMethods[1]->getCode(), 'credit_card'); + } + + public function test_it_does_not_resolve_pausepay_with_non_euro_currency(): void + { + $order = $this->getBaseOrder(); + $order->setCurrencyCode('USD'); + $supportedMethods = $this->resolver->getSupportedMethods($this->getPayment($order)); + + self::assertCount(2, $supportedMethods); + + self::assertSame($supportedMethods[0]->getCode(), 'paypal'); + self::assertSame($supportedMethods[1]->getCode(), 'credit_card'); + } + + public function test_it_does_not_resolve_pausepay_with_amount_below_500(): void + { + $order = $this->getBaseOrder(); + $order->removeItem($order->getItems()->first()); + $supportedMethods = $this->resolver->getSupportedMethods($this->getPayment($order)); + + self::assertCount(2, $supportedMethods); + + self::assertSame($supportedMethods[0]->getCode(), 'paypal'); + self::assertSame($supportedMethods[1]->getCode(), 'credit_card'); + } + + public function test_it_does_not_resolve_pausepay_with_amount_above_20000(): void + { + $order = $this->getBaseOrder(); + $order->addItem($this->getOrderItemWithUnit('Star Wars Mug', 10000000, 1)); + $supportedMethods = $this->resolver->getSupportedMethods($this->getPayment($order)); + + self::assertCount(2, $supportedMethods); + + self::assertSame($supportedMethods[0]->getCode(), 'paypal'); + self::assertSame($supportedMethods[1]->getCode(), 'credit_card'); + } + + private function getPayment(OrderInterface $order): PaymentInterface + { + $payment = new Payment(); + $payment->setMethod($this->getPaymentMethod(PausePayApi::GATEWAY_CODE)); + $payment->setCurrencyCode('EUR'); + $payment->setOrder($order); + $payment->setAmount($order->getTotal()); + + return $payment; + } + + private function getBaseOrder(): OrderInterface + { + $order = new Order(); + $order->setChannel(new Channel()); + $billingAddress = new Address(); + $billingAddress->setCountryCode('IT'); + $order->setBillingAddress($billingAddress); + $order->setCurrencyCode('EUR'); + $order->addItem($this->getOrderItemWithUnit('Star Wars Mug', 100000, 1)); + + return $order; + } + + private function getPaymentMethod(string $code): PaymentMethodInterface + { + $paypal = new PaymentMethod(); + $gateway = new GatewayConfig(); + $gateway->setFactoryName($code); + $paypal->setGatewayConfig($gateway); + $paypal->setCode($code); + return $paypal; + } + + private function getOrderItemWithUnit( + string $name, + int $unitPrice, + int $quantity, + ): OrderItem { + $orderItem = new OrderItem(); + $orderItem->setUnitPrice($unitPrice); + $orderItem->setVariantName($name); + for ($i = 0; $i < $quantity; ++$i) { + new OrderItemUnit($orderItem); + } + + return $orderItem; + } +}