<?php declare(strict_types=1);
namespace Virgin\CheckoutPlugin\Storefront\Subscriber;
use Shopware\Core\Checkout\Cart\Event\CartDeletedEvent;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
use Shopware\Core\Checkout\Cart\Transaction\TransactionProcessor;
use Shopware\Core\Checkout\Promotion\PromotionEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\Framework\Rule\Exception\UnsupportedOperatorException;
use Shopware\Core\Framework\Rule\Rule;
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Virgin\CheckoutPlugin\Utils\Services\CartServiceCalculator;
use Virgin\ProductModelExtension\Custom\ProductType\ProductTypeEntity;
use Virgin\SubscriptionsConfigurator\Utils\Services\SubscriptionsConfiguratorService;
class CartSubscriber implements EventSubscriberInterface
{
/**
* @var TransactionProcessor
*/
private $transactionProcessor;
/**
* @var CartServiceCalculator
*/
private $cartServiceCalculator;
/** @var EntityRepositoryInterface */
private $promotionRepository;
/** @var EntityRepositoryInterface */
private $ruleConditionRepository;
/** @var CartService */
private $cartService;
/**
* @var Session
*/
private $session;
/**
* @param TransactionProcessor $transactionProcessor
* @param CartServiceCalculator $cartServiceCalculator
* @param EntityRepositoryInterface $promotionRepository
* @param EntityRepositoryInterface $ruleConditionRepository
* @param CartService $cartService
* @param Session $session
*/
public function __construct(
TransactionProcessor $transactionProcessor,
CartServiceCalculator $cartServiceCalculator,
EntityRepositoryInterface $promotionRepository,
EntityRepositoryInterface $ruleConditionRepository,
CartService $cartService,
Session $session
) {
$this->transactionProcessor = $transactionProcessor;
$this->cartServiceCalculator = $cartServiceCalculator;
$this->promotionRepository = $promotionRepository;
$this->ruleConditionRepository = $ruleConditionRepository;
$this->cartService = $cartService;
$this->session = $session;
}
public static function getSubscribedEvents(): array
{
return [
CheckoutConfirmPageLoadedEvent::class => 'addCartInfo',
CartDeletedEvent::class => 'deleteCart'
];
}
public function deleteCart(CartDeletedEvent $event): void
{
$this->session->remove("promotionCode");
$this->session->remove("fullpriceTotalAmount");
unset($_SESSION['super_promo_user']);
unset($_SESSION['super_promo_flow']);
}
public function addCartInfo(CheckoutConfirmPageLoadedEvent $event): void
{
if ($event->getSalesChannelContext()->getCustomer() || isset($_SESSION['isDirectFlow'])) {
$cart = $event->getPage()->getCart();
$lineItems = $cart->getLineItems();
// The line above may not be true with new promotions and flows in future
// Check if line item has a special flow promo like Black Days promo, if so do not remove promotions and discounts
$isSpecialPromoFlow = false;
/** @var LineItem $lineItem */
foreach ($lineItems as $lineItem){
if (!is_null($lineItem->getPayloadValue('main'))) {
$productType = $lineItem->getPayloadValue('product_type');
}
if ($lineItem->getPayloadValue('isSpecialPromoFlow') === true) {
$isSpecialPromoFlow = true;
}
}
if (isset($productType) && $productType == ProductTypeEntity::SUBSCRIPTION) {
$isGift = isset($_SESSION['gift_user_params']);
$customer = $event->getSalesChannelContext()->getCustomer();
if (!$isSpecialPromoFlow && is_null($customer)) {
/** @var LineItem $lineItem */
foreach ($lineItems as $lineItem) {
if ($lineItem->getType() == 'promotion') {
if (($lineItem->getPayloadValue('code') == '' || $lineItem->getPayloadValue('exerpPromotion'))) {
$lineItems->remove($lineItem->getId());
}
}
}
} else {
if ($isGift && strpos(strtolower($event->getSalesChannelContext()->getCurrentCustomerGroup()->getName()), strtolower(SubscriptionsConfiguratorService::BOCCONI_STRING)) !== false) {
/** @var LineItem $lineItem */
foreach ($lineItems as $lineItem) {
if ($lineItem->getType() == 'promotion') {
$promotionId = $lineItem->getPayloadValue('promotionId');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('id', $promotionId));
$criteria->addAssociation('personaRules');
/** @var PromotionEntity $promotionEntity */
$promotionEntity = $this->promotionRepository
->search($criteria, Context::createDefaultContext())
->first();
$personaRules = $promotionEntity->getPersonaRules();
if (null !== $personaRules) {
foreach ($personaRules as $personaRule) {
$criteria = new Criteria();
$criteria->addFilter(new MultiFilter(
MultiFilter::CONNECTION_AND,
[
new EqualsFilter('rule_condition.type', 'customerCustomerGroup'),
new EqualsFilter('rule_condition.ruleId', $personaRule->getId()),
]
));
$condition = $this->ruleConditionRepository
->search($criteria, Context::createDefaultContext())
->first();
if ($condition) {
$customerGroupHasPromo = $this->match($condition->getValue()['operator'],
$condition->getValue()['customerGroupIds'],
[$_SESSION['gift_user_params']['customerGroupId']]);
if (!$customerGroupHasPromo) {
$this->cartService->remove($cart, $lineItem->getId(), $event->getSalesChannelContext());
}
}
}
}
}
}
}
}
}
$cart->setLineItems($this->cartServiceCalculator->setExerpPrice($lineItems, $event->getSalesChannelContext()));
$amount= $this->cartServiceCalculator->reCalculateCartAmount($event->getSalesChannelContext(), $cart, $isSpecialPromoFlow);
$cart->setPrice($amount);
$cart->setTransactions(
$this->transactionProcessor->process($cart, $event->getSalesChannelContext())
);
$event->getPage()->setCart($cart);
}
}
/**
* @param $operator
* @param $identifiers
* @param $target
* @return bool
*/
private function match($operator, $identifiers, $target)
{
switch ($operator) {
case Rule::OPERATOR_EQ:
return !empty(array_intersect($identifiers, $target));
case Rule::OPERATOR_NEQ:
return empty(array_intersect($identifiers, $target));
default:
throw new UnsupportedOperatorException($operator, Rule::class);
}
}
}