custom/plugins/SwagCommercial/src/CustomPricing/Subscriber/ProductSubscriber.php line 52

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Commercial\CustomPricing\Subscriber;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Commercial\CustomPricing\Entity\CustomPrice\CustomPriceDefinition;
  5. use Shopware\Commercial\CustomPricing\Entity\CustomPrice\Price\CustomPriceCollection;
  6. use Shopware\Commercial\CustomPricing\Entity\Field\CustomPriceField;
  7. use Shopware\Commercial\CustomPricing\Entity\FieldSerializer\CustomPriceFieldSerializer;
  8. use Shopware\Commercial\Licensing\License;
  9. use Shopware\Core\Checkout\Customer\CustomerEntity;
  10. use Shopware\Core\Content\Product\Aggregate\ProductPrice\ProductPriceCollection;
  11. use Shopware\Core\Content\Product\Aggregate\ProductPrice\ProductPriceEntity;
  12. use Shopware\Core\Content\Product\ProductEvents;
  13. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\Price;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\PriceCollection;
  16. use Shopware\Core\Framework\Uuid\Uuid;
  17. use Shopware\Core\System\SalesChannel\Entity\SalesChannelEntityLoadedEvent;
  18. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. /**
  21.  * @internal
  22.  */
  23. class ProductSubscriber implements EventSubscriberInterface
  24. {
  25.     private const CUSTOMER_PRICE_RULE '9d7b6ee6d77547309bd35f92adfe1479';
  26.     private Connection $connection;
  27.     private CustomPriceFieldSerializer $priceFieldSerializer;
  28.     /**
  29.      * @internal
  30.      */
  31.     public function __construct(
  32.         Connection $connection,
  33.         CustomPriceFieldSerializer $priceFieldSerializer
  34.     ) {
  35.         $this->connection $connection;
  36.         $this->priceFieldSerializer $priceFieldSerializer;
  37.     }
  38.     public static function getSubscribedEvents(): array
  39.     {
  40.         return [
  41.             'sales_channel.' ProductEvents::PRODUCT_LOADED_EVENT => ['salesChannelLoaded'100],
  42.         ];
  43.     }
  44.     public function salesChannelLoaded(SalesChannelEntityLoadedEvent $event): void
  45.     {
  46.         if (!License::get('CUSTOM_PRICES-4458487')) {
  47.             return;
  48.         }
  49.         /** @var array<int, SalesChannelProductEntity> $products */
  50.         $products $event->getEntities();
  51.         $salesChannelContext $event->getSalesChannelContext();
  52.         if (empty($products) || !$salesChannelContext->getCustomer()) {
  53.             return;
  54.         }
  55.         $customPrices $this->getCustomPrices($products$salesChannelContext->getCustomer());
  56.         if (\count($customPrices) === 0) {
  57.             return;
  58.         }
  59.         $salesChannelContext->setRuleIds(\array_merge($salesChannelContext->getRuleIds(), [self::CUSTOMER_PRICE_RULE]));
  60.         $prices = [];
  61.         foreach ($customPrices as $customPrice) {
  62.             $prices[$customPrice['productId']] = $this->createPriceCollections($customPrice$salesChannelContext);
  63.         }
  64.         foreach ($products as $product) {
  65.             if (isset($prices[$product->getId()])) {
  66.                 $product->assign($prices[$product->getId()]);
  67.             }
  68.         }
  69.     }
  70.     /**
  71.      * @param array{productId: string, price: array<CustomPriceCollection>|null} $customPrice
  72.      *
  73.      * @return array{price: PriceCollection, prices: ProductPriceCollection, cheapestPrice: null}
  74.      */
  75.     private function createPriceCollections(array $customPriceSalesChannelContext $salesChannelContext): ?array
  76.     {
  77.         if ($customPrice['price'] === null) {
  78.             return null;
  79.         }
  80.         $productId $customPrice['productId'];
  81.         $productPriceCollection = new ProductPriceCollection();
  82.         foreach ($customPrice['price'] as $price) {
  83.             if ($price->first() === null) {
  84.                 continue;
  85.             }
  86.             $start $price->first()->getQuantityStart();
  87.             $end $price->first()->getQuantityEnd();
  88.             $productPrice = new ProductPriceEntity();
  89.             $productPrice->setId(Uuid::randomHex());
  90.             $productPrice->setRuleId(self::CUSTOMER_PRICE_RULE);
  91.             $productPrice->setPrice($price);
  92.             $productPrice->setProductId($productId);
  93.             $productPrice->setQuantityStart($start);
  94.             $productPrice->setQuantityEnd($end);
  95.             $productPriceCollection->add($productPrice);
  96.         }
  97.         $productPriceCollection->sortByQuantity();
  98.         return [
  99.             'price' => $productPriceCollection->first() !== null $productPriceCollection->first()->getPrice() : null,
  100.             'prices' => $productPriceCollection,
  101.             'cheapestPrice' => null,
  102.         ];
  103.     }
  104.     /**
  105.      * @param array<SalesChannelProductEntity> $products
  106.      *
  107.      * @return array<int, array{productId: string, price: array<CustomPriceCollection>|null}>
  108.      */
  109.     private function getCustomPrices(array $productsCustomerEntity $customer): array
  110.     {
  111.         $productIds array_map(fn ($product) => Uuid::fromHexToBytes($product->getId()), $products);
  112.         $tmpField = new CustomPriceField('price''price');
  113.         $customerId Uuid::fromHexToBytes($customer->getId());
  114.         $customerGroupId $customer->getGroupId() ? Uuid::fromHexToBytes($customer->getGroupId()) : null;
  115.         /** @var array<int, array{productId: string, price: string|null}> $result */
  116.         $result $this->connection->createQueryBuilder()
  117.             ->select('LOWER(HEX(product_id)) as productId''price')
  118.             ->from(CustomPriceDefinition::ENTITY_NAME)
  119.             ->where('product_id IN (:productIds)')
  120.             ->andWhere('(customer_id = :customerId OR customer_group_id = :groupId)')
  121.             ->setParameter('productIds'$productIdsConnection::PARAM_STR_ARRAY)
  122.             ->setParameter('customerId'$customerId)
  123.             ->setParameter('groupId'$customerGroupId)
  124.             ->orderBy('product_id''ASC')
  125.             ->addOrderBy('customer_id''ASC')
  126.             ->execute()
  127.             ->fetchAllAssociative();
  128.         return \array_map(fn ($item) => [
  129.             'productId' => $item['productId'],
  130.             'price' => $this->priceFieldSerializer->decode($tmpField$item['price']),
  131.         ], $result);
  132.     }
  133. }