<?php declare(strict_types=1);
namespace GlobusSW6\Subscriber\Cart;
use GlobusSW6\Core\IaneoDefaults;
use GlobusSW6\Service\Cart\ShippingMethodService;
use Shopware\Core\Checkout\Cart\Event\BeforeLineItemAddedEvent;
use Shopware\Core\Checkout\Cart\Event\BeforeLineItemRemovedEvent;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Psr\Log\LoggerInterface;
class CartActionSubscriber implements EventSubscriberInterface
{
/** @var LoggerInterface */
private LoggerInterface $logger;
/** @var ShippingMethodService */
private $shippingMethodService;
/**
* @param LoggerInterface $logger
* @param ShippingMethodService $shippingMethodService
*/
public function __construct(LoggerInterface $logger, ShippingMethodService $shippingMethodService)
{
$this->logger = $logger;
$this->shippingMethodService = $shippingMethodService;
}
public static function getSubscribedEvents(): array
{
return [
BeforeLineItemAddedEvent::class => 'beforeLineItemAdded',
BeforeLineItemRemovedEvent::class => 'beforeLineItemRemoved'
];
}
/**
* @param BeforeLineItemAddedEvent $event
* @throws \Exception
*
* Note: currently (sw-6-4-5-1) only the before-events allow to add extensions to the cart
*/
public function beforeLineItemAdded(BeforeLineItemAddedEvent $event): void
{
$cart = $event->getCart();
$addedLI = $event->getLineItem();
$cartLIs = clone $cart->getLineItems();
try {
$salesChannelId = $event->getContext()->getSource()->getSalesChannelId();
} catch (\Throwable $t) {
$this->logger->info('Unable to detect salesChannelId. Use Baumarkt ID as fallback : ' . $t->getMessage());
$salesChannelId = IaneoDefaults::SALES_CHANNEL_BAUMARKT;
}
if ($addedLI->getType() !== 'product') {
return;
}
/** @var LineItem $cartLI */
foreach ($cartLIs as $key => $cartLI) {
$cartLiExtension = $cartLI->getExtensions();
if (!array_key_exists('ianeoOrderType', $cartLiExtension) || $cartLiExtension['ianeoOrderType']['orderType'] === 'reserveInStore') {
$cartLIs->remove($key);
}
}
$liExtensions = $addedLI->getExtensions();
if (!array_key_exists('ianeoOrderType', $liExtensions)) {
return;
}
// reservation cart
if ($liExtensions['ianeoOrderType']['orderType'] === 'reserveInStore' && $cartLIs->count() === 0) {
$this->shippingMethodService->changeShippingMethod(IaneoDefaults::SHIPPING_METHOD_GLOBUS_PICKUP, $cart, $event->getSalesChannelContext());
return;
}
if ($liExtensions['ianeoOrderType']['orderType'] === 'reserveInStore' && $cartLIs->count() > 0) {
return;
}
$lineItemIds = array_merge($cartLIs->getReferenceIds(), [$addedLI->getReferencedId()]);
$shippingMethods = $this->shippingMethodService->getShippingMethods($lineItemIds, $salesChannelId);
if (!array_key_exists($addedLI->getReferencedId(), $shippingMethods)) {
$this->logger->info('Unable to detect shippingMethod for ' . $addedLI->getId());
throw new \Exception('Unable to detect shippingMethod for ' . $addedLI->getId());
}
$shippingMethodofAddedLI = $shippingMethods[$addedLI->getReferencedId()];
// check shipping method of cart and compare if with new lineitem. Select shipping method of higher priority
$extensions = $cart->getExtensions();
if (!array_key_exists('selectedShippingMethod', $extensions)) {
$this->shippingMethodService->changeShippingMethod($shippingMethodofAddedLI, $cart, $event->getSalesChannelContext());
} else {
try {
/** @var string $selectedShippingMethod */
$selectedShippingMethod = $extensions['selectedShippingMethod']['shippingMethod'];
} catch (\Throwable $t) {
$selectedShippingMethod = $extensions['selectedShippingMethod']; // handling of old carts that still have a wrong structure
}
if ($this->shippingMethodService->comparePriority($shippingMethodofAddedLI, $selectedShippingMethod)) {
$this->shippingMethodService->changeShippingMethod($shippingMethodofAddedLI, $cart, $event->getSalesChannelContext());
}
}
}
/**
* @param BeforeLineItemRemovedEvent $event
* @throws \Exception
*
* Note: currently (sw-6-4-5-1) only the before-events allow to add extensions to the cart
*/
public function beforeLineItemRemoved(BeforeLineItemRemovedEvent $event): void
{
$removedLI = $event->getLineItem();
$liExtensions = $removedLI->getExtensions();
if (!array_key_exists('ianeoOrderType', $liExtensions)) {
return;
}
if ($liExtensions['ianeoOrderType']['orderType'] === 'reserveInStore') {
return;
}
if ($removedLI->getType() !== 'product') {
return;
}
try {
$salesChannelId = $event->getContext()->getSource()->getSalesChannelId();
} catch (\Throwable $t) {
$this->logger->info('Unable to detect salesChannelId. Use Baumarkt ID as fallback : ' . $t->getMessage());
$salesChannelId = IaneoDefaults::SALES_CHANNEL_BAUMARKT;
}
$cart = $event->getCart();
$cartLIs = clone $cart->getLineItems();
// remove non-product-type lineItems from calculation
foreach ($cartLIs as $id => $cartLI) {
$cartLiExtension = $cartLI->getExtensions();
if (!array_key_exists('ianeoOrderType', $cartLiExtension)) {
$cartLIs->remove($id);
continue;
}
if ($cartLiExtension['ianeoOrderType']['orderType'] === 'reserveInStore' || $cartLI->getType() !== 'product') {
$cartLIs->remove($id);
continue;
}
}
if (count($cartLIs) === 0) {
// set cart shipping method to reserveInStore
$this->shippingMethodService->changeShippingMethod(IaneoDefaults::SHIPPING_METHOD_GLOBUS_DHL_BAUMARKT, $cart, $event->getSalesChannelContext());
return;
}
$shippingMethods = $this->shippingMethodService->getShippingMethods($cartLIs->getReferenceIds(), $salesChannelId);
// check which shipping method now has highest priority
$highestPriorityShippingMethod = $this->shippingMethodService->getHighestPriorityShippingMethod($shippingMethods);
if (is_null($highestPriorityShippingMethod)){
$this->logger->info('Unable to detect shippingMethod of highest priority: ' . $cart->getToken());
throw new \Exception('Unable to detect shippingMethod of highest priority: ' . $cart->getToken());
}
$extensions = $cart->getExtensions();
if (!array_key_exists('selectedShippingMethod', $extensions)) {
$this->logger->info('No shippingMethod selected for cart: ' . $cart->getToken());
throw new \Exception('No shippingMethod selected for cart: ' . $cart->getToken());
}
if ($highestPriorityShippingMethod !== $extensions['selectedShippingMethod']['shippingMethod']) {
$this->shippingMethodService->changeShippingMethod($highestPriorityShippingMethod, $cart, $event->getSalesChannelContext());
}
}
}