Skip to content

Commit

Permalink
Add payments method resolver for pausepay
Browse files Browse the repository at this point in the history
  • Loading branch information
LucaGallinari committed Sep 10, 2024
1 parent cdfd969 commit 7e130ed
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 0 deletions.
9 changes: 9 additions & 0 deletions config/services/resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
]);
};
103 changes: 103 additions & 0 deletions src/Resolver/PausePayPaymentMethodsResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

declare(strict_types=1);

namespace Webgriffe\SyliusPausePayPlugin\Resolver;

use Sylius\Component\Core\Model\AddressInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PaymentInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Component\Core\Repository\PaymentMethodRepositoryInterface;
use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
use Webgriffe\SyliusPausePayPlugin\Payum\PausePayApi;
use Webmozart\Assert\Assert;

final class PausePayPaymentMethodsResolver implements PaymentMethodsResolverInterface
{
public function __construct(
private PaymentMethodRepositoryInterface $paymentMethodRepository,
) {
}

/**
* @param BasePaymentInterface|PaymentInterface $subject
*
* @return PaymentMethodInterface[]
*/
public function getSupportedMethods(BasePaymentInterface $subject): array
{
Assert::true($this->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;
}
}
155 changes: 155 additions & 0 deletions tests/Unit/Resolver/PausePayPaymentMethodsResolverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php

declare(strict_types=1);

namespace Tests\Webgriffe\SyliusPausePayPlugin\Unit\Resolver;

use PHPUnit\Framework\TestCase;
use Sylius\Bundle\PayumBundle\Model\GatewayConfig;
use Sylius\Component\Core\Model\Address;
use Sylius\Component\Core\Model\Channel;
use Sylius\Component\Core\Model\Order;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\OrderItem;
use Sylius\Component\Core\Model\OrderItemUnit;
use Sylius\Component\Core\Model\Payment;
use Sylius\Component\Core\Model\PaymentInterface;
use Sylius\Component\Core\Model\PaymentMethod;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Component\Core\Repository\PaymentMethodRepositoryInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
use Webgriffe\SyliusPausePayPlugin\Payum\PausePayApi;
use Webgriffe\SyliusPausePayPlugin\Resolver\PausePayPaymentMethodsResolver;

final class PausePayPaymentMethodsResolverTest extends TestCase
{
private PaymentMethodsResolverInterface $resolver;

protected function setUp(): void
{
$repoMock = $this->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;
}
}

0 comments on commit 7e130ed

Please sign in to comment.