<?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\EntityRepositoryInterface;
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 EntityRepositoryInterface
*/
private $productRepository;
/**
* @var Session
*/
private $session;
public function __construct(
EntityRepository $repository,
PercentagePriceCalculator $calculator,
LineItemGroupBuilder $groupBuilder,
EntityRepositoryInterface $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->getName());
$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() ? $promotion->getValidUntil()->getTimestamp():null);
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'];
if ($promotionObject->getIsPromoValoreAggiunto()) {
$discountLineItem->setPayloadValue('isPromoValoreAggiunto', true);
$discountLineItem->setPayloadValue('cashbackType', $promotionObject->getCashbackType());
$discountLineItem->setPayloadValue('cashbackValue', (float) $promotionObject->getCashbackValue());
if($promotionObject->getCashbackType() != 'no_cashback') {
$criteria = new Criteria();
$criteria->addAssociation('productType');
$criteria->addFilter(new EqualsFilter('product.productType.name', ProductTypeEntity::CASHBACK));
$searchResult = $this->productRepository->search($criteria, $context->getContext())->first();
$discountLineItem->setPayloadValue('cashbackCenterId', $searchResult->getCustomFields()['virgin_exerp_centerid']);
$discountLineItem->setPayloadValue('cashbackProductId', $searchResult->getCustomFields()['virgin_exerp_productid']);
}
if($promotionObject->getProduct()) {
$promoOmaggioProductType = $promotionObject->getProduct()->getExtensions()['productType']->getName();
$discountLineItem->setPayloadValue('productOmaggioType', $promoOmaggioProductType);
if(array_key_exists('virgin_exerp_centerid', $promotionObject->getProduct()->getCustomFields())) {
$discountLineItem->setPayloadValue('productOmaggioCenterId', $promotionObject->getProduct()->getCustomFields()['virgin_exerp_centerid']);
}
if(array_key_exists('virgin_exerp_productid', $promotionObject->getProduct()->getCustomFields())) {
$discountLineItem->setPayloadValue('productOmaggioProductId', $promotionObject->getProduct()->getCustomFields()['virgin_exerp_productid']);
}
if(array_key_exists('virgin_exerp_externalid', $promotionObject->getProduct()->getCustomFields())) {
$discountLineItem->setPayloadValue('productOmaggioExternalId', $promotionObject->getProduct()->getCustomFields()['virgin_exerp_externalid']);
}
if(array_key_exists('virgin_exerp_type', $promotionObject->getProduct()->getCustomFields())) {
$discountLineItem->setPayloadValue('productOmaggioExerpType', $promotionObject->getProduct()->getCustomFields()['virgin_exerp_type']);
}
$discountLineItem->setPayloadValue('productOmaggioQuantity', 1);
}
}
$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']){
array_push($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);
}
}