<?php declare(strict_types=1);
namespace Econsor\Shopware\AtBitConfiguratorConnector\Subscriber;
use Econsor\Shopware\AtBitConfiguratorConnector\AtBitSessionKeys;
use Econsor\Shopware\AtBitConfiguratorConnector\Services\AtBitPriceCalculator;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\System\SalesChannel\Event\SalesChannelContextRestoredEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
/**
* Shopware's login cart-merge (SalesChannelContextRestorer::mergeCart) treats every
* stackable line item as mergeable regardless of whether it already exists in the
* customer's persisted cart, so if a configurator line item id is present in both the
* guest cart (re-injected from session on every calculation) and the customer's saved
* cart, its quantity gets summed again on login. This corrects the quantity back to
* what our own session bookkeeping considers canonical, right after the merge lands.
*/
class AtBitCartMergeFix implements EventSubscriberInterface
{
private $session;
private $cartService;
private $priceCalculator;
public function __construct(Session $session, CartService $cartService, AtBitPriceCalculator $priceCalculator)
{
$this->session = $session;
$this->cartService = $cartService;
$this->priceCalculator = $priceCalculator;
}
public static function getSubscribedEvents(): array
{
return [
SalesChannelContextRestoredEvent::class => 'onContextRestored',
];
}
public function onContextRestored(SalesChannelContextRestoredEvent $event): void
{
if (!$this->session->has(AtBitSessionKeys::CONFIGURATOR_PRODUCTS)) {
return;
}
$context = $event->getRestoredSalesChannelContext();
$products = $this->session->get(AtBitSessionKeys::CONFIGURATOR_PRODUCTS);
$cart = $this->cartService->getCart($context->getToken(), $context);
$fixed = false;
/** @var LineItem $sessionProduct */
foreach ($products as $id => $sessionProduct) {
$cartItem = $cart->get($id);
if (!$cartItem) {
continue;
}
$expectedQuantity = $sessionProduct->getQuantity();
if ($cartItem->getQuantity() === $expectedQuantity) {
continue;
}
/** @var ArrayStruct|null $extension */
$extension = $cartItem->getExtension('atbitConfiguration');
if (!$extension instanceof ArrayStruct) {
continue;
}
$cartItem->setQuantity($expectedQuantity);
$cartItem->setPrice($this->priceCalculator->calculate(
(float) $extension->get('GesamtpreisOhneMwSt'),
(float) $extension->get('MwSt'),
$expectedQuantity
));
$fixed = true;
}
if ($fixed) {
$this->cartService->recalculate($cart, $context);
}
}
}