<?php declare(strict_types=1);
namespace Virgin\Promotions\Core\Checkout\Promotion\Cart;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\CartBehavior;
use Shopware\Core\Checkout\Cart\CartProcessorInterface;
use Shopware\Core\Checkout\Cart\Error\ErrorCollection;
use Shopware\Core\Checkout\Cart\LineItem\CartDataCollection;
use Shopware\Core\Checkout\Cart\LineItem\Group\LineItemGroupBuilder;
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
use Shopware\Core\Checkout\Cart\LineItem\LineItemCollection;
use Shopware\Core\Checkout\Cart\Price\PercentagePriceCalculator;
use Shopware\Core\Checkout\Cart\Price\Struct\PercentagePriceDefinition;
use Shopware\Core\Checkout\Cart\Rule\CartRuleScope;
use Shopware\Core\Checkout\Promotion\PromotionEntity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\Session\Session;
use Virgin\ProductModelExtension\Custom\ProductType\ProductTypeEntity;
use Virgin\Promotions\Custom\PromotionAttributes\PromotionAttributesEntity;
class ExerpPromotionProcessor implements CartProcessorInterface
{
/**
* @var EntityRepository
*/
private $promotionAttributesRepository;
/**
* @var PercentagePriceCalculator
*/
private $calculator;
/**
* @var LineItemGroupBuilder
*/
private $groupBuilder;
/**
* @var EntityRepository
*/
private $productRepository;
/**
* @var Session
*/
private $session;
public function __construct(
EntityRepository $repository,
PercentagePriceCalculator $calculator,
LineItemGroupBuilder $groupBuilder,
EntityRepository $productRepository,
Session $session
) {
$this->promotionAttributesRepository = $repository;
$this->calculator = $calculator;
$this->groupBuilder = $groupBuilder;
$this->productRepository = $productRepository;
$this->session = $session;
}
public function process(
CartDataCollection $data,
Cart $original,
Cart $toCalculate,
SalesChannelContext $context,
CartBehavior $behavior
): void {
/** @var array $exerpPromotions */
$exerpPromotions = $data->get('exerpPromotions');
$productLineItemCollection = new LineItemCollection();
$promotion = null;
foreach ($exerpPromotions as $exerpPromotion) {
/** @var PromotionEntity $promotion */
$promotion = $exerpPromotion['promotion'];
$discountLineItem = new LineItem(
$promotion->getId(),
'promotion',
$exerpPromotion['code'],
1
);
if(!$promotion->getDiscounts()->getElements()){
$discountLineItem->setLabel($promotion->getTranslation('name'));
$discountLineItem->setGood(false);
$discountLineItem->setStackable(true);
$discountLineItem->setRemovable(true);
$discountLineItem->setRequirement($promotion->getPreconditionRule());
$discountLineItem->setPayloadValue('promotionId', $promotion->getId());
$discountLineItem->setPayloadValue('code', $exerpPromotion['code']);
$discountLineItem->setPayloadValue('exerpPromotion', true);
$discountLineItem->setPayloadValue('badgeText', $exerpPromotion['attribute']->getBadgeText());
$discountLineItem->setPayloadValue('exerpPromotionDescription', $exerpPromotion['attribute']->getDescription());
$discountLineItem->setPayloadValue('exerpPromotionCode', $exerpPromotion['attribute']->getExerpCode());
$discountLineItem->setPayloadValue('isSpecialPromoFlow', $exerpPromotion['attribute']->getIsSpecialPromoFlow());
$discountLineItem->setPayloadValue('validUntil', $promotion->getValidUntil()?->getTimestamp());
if (!empty($promoProrataDate = $exerpPromotion['attribute']->getPromoProrataDate())) {
if($promoProrataDate->format('Y-m-d') < date("Y-m-d")) {
$promoProrataDateFormatted = date("Y-m-d");
} else {
$promoProrataDateFormatted = $promoProrataDate->format('Y-m-d');
}
$discountLineItem->setPayloadValue('newPromotionDate', $promoProrataDateFormatted);
if(!isset($_SESSION['prorata_date'])) {
$_SESSION['prorata_date'] = $promoProrataDateFormatted;
}
}
$discountLineItem->setPayloadValue('promoWithoutDiscount', true);
/** @var PromotionAttributesEntity $promotionObject */
$promotionObject = $exerpPromotion['attribute'];
$definition = new PercentagePriceDefinition(
-100,
);
$discountLineItem->setPriceDefinition($definition);
// calculate price
$discountLineItem->setPrice(
$this->calculator->calculate(
$definition->getPercentage(),
$productLineItemCollection->getPrices(),
$context
)
);
$selectedStartDate = $this->session->get('prorata_date');
if (!$this->isRequirementValid($discountLineItem, $toCalculate, $context, $selectedStartDate)) {
continue;
}
// add discount to new cart
$toCalculate->add($discountLineItem);
$errors = $toCalculate->getErrors()->getElements();
$errorToCalculate = [];
foreach ($errors as $error){
if($error->getCode()!=null && $error->getCode() != $exerpPromotion['code']){
$errorToCalculate[] = $error;
}
}
$toCalculate->setErrors(new ErrorCollection($errorToCalculate));
}
}
$errorToCalculate = [];
foreach ($toCalculate->getErrors() as $error){
if(!$error instanceof \Shopware\Core\Checkout\Promotion\Cart\Error\PromotionNotFoundError){
$errorToCalculate[] = $error;
}
}
$toCalculate->setErrors(new ErrorCollection($errorToCalculate));
}
private function isRequirementValid(LineItem $lineItem, Cart $calculated, SalesChannelContext $context, $selectedStartDate=null): bool
{
if (!$lineItem->getRequirement()) {
return true;
}
if ($selectedStartDate && $lineItem->getPayload()['validUntil'] && $selectedStartDate>$lineItem->getPayload()['validUntil']) {
return false;
}
$scopeWithoutLineItem = new CartRuleScope($calculated, $context);
$data = $scopeWithoutLineItem->getCart()->getData();
$data->set(LineItemGroupBuilder::class, $this->groupBuilder);
return $lineItem->getRequirement()->match($scopeWithoutLineItem);
}
}