Search code examples
shopwareshopware6

How can I programatically hide specific payment method in Shopware 6


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.


Solution

  • 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;
                }
            }
        }
    }