<?php declare(strict_types=1);
namespace MoorlProductAccessories\Core\Service;
use MoorlProductAccessories\Core\Content\Accessory\AccessoryCollection;
use MoorlProductAccessories\Core\Content\Accessory\AccessoryEntity;
use MoorlProductAccessories\Core\Content\Category\CategoryCollection;
use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
use Shopware\Core\Checkout\Cart\Price\Struct\ListPrice;
use Shopware\Core\Content\Media\Pathname\UrlGeneratorInterface;
use Shopware\Core\Content\Product\SalesChannel\Price\AbstractProductPriceCalculator;
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\DefinitionInstanceRegistry;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepositoryInterface;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class ProductAccessoriesService
{
private Context $context;
private SalesChannelContext $salesChannelContext;
private DefinitionInstanceRegistry $definitionInstanceRegistry;
private SystemConfigService $systemConfigService;
private SalesChannelRepositoryInterface $salesChannelProductRepository;
private AbstractProductPriceCalculator $productPriceCalculator;
private UrlGeneratorInterface $urlGenerator;
public function __construct(
DefinitionInstanceRegistry $definitionInstanceRegistry,
SystemConfigService $systemConfigService,
SalesChannelRepositoryInterface $salesChannelProductRepository,
AbstractProductPriceCalculator $productPriceCalculator,
UrlGeneratorInterface $urlGenerator
)
{
$this->definitionInstanceRegistry = $definitionInstanceRegistry;
$this->systemConfigService = $systemConfigService;
$this->salesChannelProductRepository = $salesChannelProductRepository;
$this->productPriceCalculator = $productPriceCalculator;
$this->urlGenerator = $urlGenerator;
}
public function getProduct(string $productId, SalesChannelContext $salesChannelContext): ?SalesChannelProductEntity
{
$this->salesChannelContext = $salesChannelContext;
$criteria = new Criteria([$productId]);
$this->enrichProductCriteria($criteria);
$product = $this->salesChannelProductRepository->search($criteria, $salesChannelContext)->get($productId);
$this->enrichProductEntity($product);
return $product;
}
public function enrichProductEntity(SalesChannelProductEntity $product): void
{
if ($product->getExtension('moorlPa')) {
$accessoryCollection = $product->getExtension('moorlPa');
} else {
$accessoryCollection = new AccessoryCollection();
}
$productStreams = $product->getStreams();
if ($productStreams) {
foreach ($productStreams as $productStream) {
if ($productStream->getExtension('moorlPa')) {
$accessoryCollection->merge($productStream->getExtension('moorlPa'));
}
}
}
/* Deprecated: Use product streams */
$categories = $product->getCategories();
if ($categories) {
/** @var CategoryCollection|null $excluded */
$excluded = $product->getExtension('moorlPaCategories');
foreach ($categories as $category) {
if ($excluded && $excluded->has($category->getId())) {
continue;
}
if ($category->getExtension('moorlPa')) {
$accessoryCollection->merge($category->getExtension('moorlPa'));
}
}
}
$product->removeExtension('moorlPa');
$product->addExtension('moorlPa', $accessoryCollection->getCategories());
}
public function handlePrice(AccessoryEntity $accessory): void
{
$product = $accessory->getAccessory();
$this->productPriceCalculator->calculate([$product], $this->salesChannelContext);
$accessory->setCalculatedPrice($product->getCalculatedPrice());
/* Early return - no price manipulation*/
if (!$this->systemConfigService->get('MoorlProductAccessories.config.bundles')) {
return;
}
if ($accessory->getCustomPrice() && $accessory->getPrice() === null) {
/* Deprecated calculation */
$oldCalculatedPrice = $product->getCalculatedPrice();
$listPrice = $oldCalculatedPrice->getListPrice();
if (!$listPrice) {
$listPrice = ListPrice::createFromUnitPrice(
$accessory->getRawPrice(),
$oldCalculatedPrice->getUnitPrice()
);
} else {
$listPrice = ListPrice::createFromUnitPrice(
$accessory->getRawPrice(),
$listPrice->getPrice()
);
}
$accessory->setCalculatedPrice(new CalculatedPrice(
$accessory->getRawPrice(),
$accessory->getRawPrice(),
$oldCalculatedPrice->getCalculatedTaxes(),
$oldCalculatedPrice->getTaxRules(),
$oldCalculatedPrice->getQuantity(),
$oldCalculatedPrice->getReferencePrice(),
$listPrice
));
} else if ($accessory->getCustomPrice() && $accessory->getPrice()) {
/* New calculation */
$oldCalculatedPrice = $product->getCalculatedPrice();
$product->setPrice($accessory->getPrice());
$this->productPriceCalculator->calculate([$product], $this->salesChannelContext);
$newCalculatedPrice = $product->getCalculatedPrice();
$listPrice = $oldCalculatedPrice->getListPrice();
if (!$listPrice) {
$listPrice = ListPrice::createFromUnitPrice(
$newCalculatedPrice->getUnitPrice(),
$oldCalculatedPrice->getUnitPrice()
);
} else {
$listPrice = ListPrice::createFromUnitPrice(
$newCalculatedPrice->getUnitPrice(),
$listPrice->getPrice()
);
}
$accessory->setCalculatedPrice(new CalculatedPrice(
$newCalculatedPrice->getUnitPrice(),
$newCalculatedPrice->getTotalPrice(),
$newCalculatedPrice->getCalculatedTaxes(),
$newCalculatedPrice->getTaxRules(),
$newCalculatedPrice->getQuantity(),
$newCalculatedPrice->getReferencePrice(),
$listPrice
));
}
}
public function enrichProductCriteria(?Criteria $criteria = null): Criteria
{
if (!$criteria) {
$criteria = new Criteria();
}
$criteria->addAssociations([
'moorlPaCategories',
'moorlPa.accessory.cover.media',
'moorlPa.accessory.options',
'streams.moorlPa.accessory.cover.media',
'streams.moorlPa.accessory.options',
/* Deprecated: Use product streams */
'categories.moorlPa.accessory.cover.media',
'categories.moorlPa.accessory.options',
]);
return $criteria;
}
/**
* @param SalesChannelContext $salesChannelContext
*/
public function setSalesChannelContext(SalesChannelContext $salesChannelContext): void
{
$this->salesChannelContext = $salesChannelContext;
$this->context = $salesChannelContext->getContext();
}
}