How can I programatically hide specific payment method in Shopware 6

138 Views Asked by At

I am trying to hide certain payment method (a custom one, let's call it MyPaygate) on checkou/confirm page if certain currency is selected. I have tried several different aproaches, but nothing worked. I am trying to use Subscriber for an event CheckoutConfirmPageLoadedEvent but it doesn't seam to be ever triggered.

EDIT: after Uwe's suggestion I came up with this:

src/Core/Checkout/Payment/SalesChannel/DecoratedPaymentMethodRoute.php

<?php declare(strict_types=1);

namespace Test\Paygate\Core\Checkout\Payment\SalesChannel;

use Shopware\Core\Checkout\Payment\SalesChannel\AbstractPaymentMethodRoute;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Checkout\Payment\SalesChannel\PaymentMethodRoute;
use Symfony\Component\HttpFoundation\Request;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\Checkout\Payment\SalesChannel\PaymentMethodRouteResponse;

class DecoratedPaymentMethodRoute extends AbstractPaymentMethodRoute
{
    private $originalService;

    public function __construct(PaymentMethodRoute $originalService)
    {
        $this->originalService = $originalService;
    }

    public function load(Request $request, SalesChannelContext $context, Criteria $criteria): PaymentMethodRouteResponse
    {
        $response = $this->originalService->load($request, $context, $criteria);

        $paymentMethods = $response->getPaymentMethods()->filter(function ($paymentMethod) use ($context) {
            if ($context->getCurrency()->getIsoCode() === 'EUR' && $paymentMethod->getHandlerIdentifier() === 'TestPaygate') {
                return false;
            }
            return true;
        });

        $response->setPaymentMethods($paymentMethods);
        return $response;
    }
    public function getDecorated(): PaymentMethodRoute
    {
        return $this->originalService;
    }
}

Relevant part of services.xml:

<service id="Test\Paygate\Core\Checkout\Payment\SalesChannel\DecoratedPaymentMethodRoute" class="Test\Paygate\Core\Checkout\Payment\SalesChannel\DecoratedPaymentMethodRoute">
            <argument type="service" id="Shopware\Core\Checkout\Payment\SalesChannel\PaymentMethodRoute" />
            <tag name="shopware.sales_channel.route_decorator"/>
        </service>

It still doesn't work. I have tried to log something from load & construct methods and nothing happens, so it seams like the methods are not even triggered.

2

There are 2 best solutions below

0
On BEST ANSWER

I ended up using following code for CheckoutConfirmPageLoadedEvent:

<?php declare(strict_types=1);

namespace MyPaymentMethod\Core\Checkout\Payment\SalesChannel;

use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class CheckoutConfirmSubscriber
 * @package MyPaymentMethod\Paygate\Subscriber
 */
class CheckoutConfirmSubscriber implements EventSubscriberInterface
{

    private SystemConfigService $systemConfigService;

    /**
     * @param SystemConfigService $systemConfigService
     */
    public function __construct(SystemConfigService $systemConfigService)
    {
        $this->systemConfigService = $systemConfigService;
    }

    /**
     * @return string[]
     */
    public static function getSubscribedEvents(): array
    {
        return [
            CheckoutConfirmPageLoadedEvent::class => 'onConfirmPageLoaded'
        ];
    }

    /**
     * @param CheckoutConfirmPageLoadedEvent $event
     * @return void
     */
    public function onConfirmPageLoaded(CheckoutConfirmPageLoadedEvent $event)
    {
        $salesChannelContext = $event->getSalesChannelContext();
        $currencyCode = $salesChannelContext->getCurrency()->getIsoCode();
        $config = $this->systemConfigService->get('MyPaymentMethod.config');
        if (empty($config['configByCurrency'][$currencyCode])) {
            $this->removeMyPaymentMethod($event->getPage()->getPaymentMethods());
        }
    }

    /**
     * @param $paymentMethods
     * @return void
     */
    private function removeMyPaymentMethod($paymentMethods): void
    {
        foreach ($paymentMethods as $paymentMethod) {
            if ($paymentMethod->getHandlerIdentifier() === 'MyPaymentMethod\Payment\MyPaymentPaygateHandler') {
                $paymentMethods->remove($paymentMethod->getId());
                break;
            }
        }
    }
}
0
On

If you're not limited to programmatic removal, you can edit the payment method's availability rule (or set one, if none is set). That rule can then check, if a particular currency is not used.

For programmatic removal, you can decorate \Shopware\Core\Checkout\Payment\SalesChannel\AbstractPaymentMethodRoute and filter the default PaymentMethodRouteResponse further with your custom logic.