<?php declare(strict_types=1);
namespace Shopware\B2B\Cart\BridgePlatform;
use Shopware\B2B\Order\BridgePlatform\OrderContextCreatedEvent;
use Shopware\B2B\Order\Framework\OrderContext;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
use Shopware\Core\Checkout\Cart\Order\CartConvertedEvent;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
abstract class CartFinishSubscriber implements EventSubscriberInterface
{
private const PRIORITY_EARLY = 10;
/**
* @var CartConvertedEvent
*/
protected $cartConvertedEvent;
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
public function __construct(EventDispatcherInterface $eventDispatcher)
{
$this->eventDispatcher = $eventDispatcher;
}
public static function getSubscribedEvents(): array
{
return [
CartConvertedEvent::class => ['initializeState', self::PRIORITY_EARLY],
CheckoutOrderPlacedEvent::class => ['handleCreatedOrder', self::PRIORITY_EARLY],
];
}
public function initializeState(CartConvertedEvent $event): void
{
$this->cartConvertedEvent = $event;
}
public function handleCreatedOrder(CheckoutOrderPlacedEvent $event): void
{
$this->testStateValid($event);
$orderContext = $this->onCartFinish(
$this->cartConvertedEvent->getCart(),
$event->getOrder(),
$this->cartConvertedEvent->getSalesChannelContext()
);
if ($orderContext) {
$this->eventDispatcher->dispatch(new OrderContextCreatedEvent($orderContext));
}
$this->reset();
}
abstract protected function onCartFinish(Cart $cart, OrderEntity $orderEntity, SalesChannelContext $salesChannelContext): ?OrderContext;
protected function getCartState(): CartState
{
return $this
->cartConvertedEvent
->getCart()
->getExtension(CartState::NAME);
}
/**
* @internal
*/
protected function testStateValid(CheckoutOrderPlacedEvent $orderPlacedEvent): void
{
if (!$this->cartConvertedEvent) {
throw new CartFinishException('Placing order without dispatching cart converted');
}
$orderNumber = $this->cartConvertedEvent->getConvertedCart()['orderNumber'];
if ($orderNumber !== $orderPlacedEvent->getOrder()->getOrderNumber()) {
throw new CartFinishException('CheckoutOrderPlacedEvent contains different order number than CartConvertedEvent');
}
$salesChannelContext = $this->cartConvertedEvent->getSalesChannelContext();
if ($salesChannelContext->getSalesChannel()->getId() !== $orderPlacedEvent->getSalesChannelId()) {
throw new CartFinishException('SalesChannel id differs between events');
}
}
private function reset(): void
{
$this->cartConvertedEvent = null;
}
}