How can I programatically hide specific payment method in Shopware 6

132 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 answers

0
Juraj.Lorinc 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
Uwe Kleinmann 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.