custom/plugins/WbfkBundles/src/Subscriber/PriceMachineSubscriber.php line 93

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Wbfk\Bundles\Subscriber;
  3. use ApplifactionPriceMachine\Event\BasePriceCalculatedEvent;
  4. use ApplifactionPriceMachine\Event\BeforeProductPricesCalculateEvent;
  5. use ApplifactionPriceMachine\Event\ProductPricesCalculatedEvent;
  6. use ApplifactionPriceMachine\Service\ProductPriceCalculationService;
  7. use Doctrine\DBAL\Connection;
  8. use Psr\Log\LoggerInterface;
  9. use Shopware\Core\Defaults;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. class PriceMachineSubscriber implements EventSubscriberInterface
  13. {
  14.     public function __construct(
  15.         private readonly Connection                      $connection,
  16.         private readonly ?ProductPriceCalculationService $productPriceCalculationService,
  17.         private readonly EntityRepository                $productRepository,
  18.         private readonly ?LoggerInterface                $logger
  19.     )
  20.     {
  21.     }
  22.     public static function getSubscribedEvents(): array
  23.     {
  24.         return [
  25.             BasePriceCalculatedEvent::class => 'calculateBundleChildrenSummaryPrice',
  26.             ProductPricesCalculatedEvent::class => 'runBundleParentPriceCalculations',
  27.             BeforeProductPricesCalculateEvent::class => 'runBundleParentBasePriceCalculation'
  28.         ];
  29.     }
  30.     public function calculateBundleChildrenSummaryPrice(BasePriceCalculatedEvent $event): void
  31.     {
  32.         if ($event->hasTemporaryPrice() && !$event->isListPrice()) return;
  33.         $bundleChildrenPriceSql 'SELECT 
  34.                     LOWER(HEX(cp.id)) AS child_product_id,
  35.                     cpp.quantity_start AS product_price_quantity_start,
  36.                     bp.quantity AS quantity,
  37.                     LOWER(HEX(cpp.rule_id)) AS rule_id,
  38.                     IFNULL(cpp.price, IFNULL(cp.price, cpa.price)) AS price
  39.                 FROM wbfk_bundle_product bp
  40.                 INNER JOIN product cp ON bp.child_product_id = cp.id AND bp.child_product_version_id = cp.version_id
  41.                 LEFT JOIN product_price cpp ON cpp.product_id = cp.id 
  42.                    AND cpp.product_version_id = cp.version_id 
  43.                    AND :quantity >= cpp.quantity_start  
  44.                    AND (:quantity <= cpp.quantity_end || cpp.quantity_end IS NULL) 
  45.                    AND LOWER(HEX(cpp.rule_id)) = :ruleId
  46.                 LEFT JOIN product cpa ON cp.parent_id = cpa.id AND cp.version_id = cpa.version_id
  47.                 WHERE LOWER(HEX(bp.product_id)) = :productId
  48.                    AND LOWER(HEX(bp.product_version_id)) = :versionId
  49.                 ORDER BY cp.id ASC, cpp.quantity_start ASC';
  50.         $bundleChildrenPriceResults $this->connection->fetchAllAssociative($bundleChildrenPriceSql, [
  51.             'quantity' => $event->getQuantityStart(),
  52.             'ruleId' => $event->getRuleId(),
  53.             'productId' => $event->getProductId(),
  54.             'versionId' => Defaults::LIVE_VERSION
  55.         ]);
  56.         $totalNet 0;
  57.         $totalGross 0;
  58.         foreach ($bundleChildrenPriceResults as $bundleChildrenPriceResult) {
  59.             $childProductId $bundleChildrenPriceResult['child_product_id'];
  60.             $quantity $bundleChildrenPriceResult['quantity'];
  61.             $priceRaw $bundleChildrenPriceResult['price'];
  62.             $priceArray json_decode($bundleChildrenPriceResult['price'], true);
  63.             if (isset($priceArray[$event->getCurrencyId()])) {
  64.                 $totalGross += $priceArray[$event->getCurrencyId()]['gross'] * $quantity;
  65.                 $totalNet += $priceArray[$event->getCurrencyId()]['net'] * $quantity;
  66.             }
  67.         }
  68.         // Modify event price
  69.         if ($totalNet === || $totalGross === 0) {
  70.             $event->setPrice(null);
  71.         } else {
  72.             $eventPrice $event->getPrice();
  73.             $eventPrice['gross'] = $totalGross;
  74.             $eventPrice['net'] = $totalNet;
  75.             $event->setPrice($eventPrice);
  76.         }
  77.     }
  78.     public function runBundleParentPriceCalculations(ProductPricesCalculatedEvent $event)
  79.     {
  80.         if (!$this->productPriceCalculationService) return;
  81.         $selectBundleParentsSql = <<<SQL
  82.             SELECT LOWER(HEX(product_id)) AS product_id
  83.             FROM wbfk_bundle_product bp
  84.             WHERE 
  85.                 LOWER(HEX(bp.product_version_id)) = :versionId AND
  86.                 LOWER(HEX(bp.child_product_id)) = :childProductId AND
  87.                 LOWER(HEX(bp.child_product_version_id)) = :versionId
  88.             GROUP BY bp.product_id
  89.         SQL;
  90.         $bundleChildrenPriceResults $this->connection->fetchAllAssociative($selectBundleParentsSql, [
  91.             'childProductId' => $event->getProductId(),
  92.             'versionId' => Defaults::LIVE_VERSION
  93.         ]);
  94.         foreach ($bundleChildrenPriceResults as $bundleChildrenPriceResult) {
  95.             $this->productPriceCalculationService->runProductPriceCalculation($bundleChildrenPriceResult['product_id'], $event->isDryRun());
  96.         }
  97.     }
  98.     public function runBundleParentBasePriceCalculation(BeforeProductPricesCalculateEvent $event)
  99.     {
  100.         if (!$this->productPriceCalculationService) return;
  101.         $productId $event->getProductId();
  102.         // Check if product is a bundle parent with no active temporary prices
  103.         $bundleParentCheckSql = <<<SQL
  104.             SELECT p.price AS price
  105.             FROM product p
  106.             INNER JOIN wbfk_bundle_product bp ON p.id = bp.product_id AND p.version_id = bp.product_version_id
  107.             LEFT JOIN apm_temporary_price atp ON atp.product_id = p.id AND 
  108.                                                  atp.product_version_id = p.version_id AND 
  109.                                                  :currentDate >= atp.valid_from AND
  110.                                                  :currentDate <= atp.valid_to
  111.             WHERE 
  112.                 LOWER(HEX(bp.product_version_id)) = :versionId AND
  113.                 LOWER(HEX(bp.product_id)) = :productId AND
  114.                 atp.id IS NULL
  115.             LIMIT 1
  116.         SQL;
  117.         $bundleParentCheckResults $this->connection->fetchAllAssociative($bundleParentCheckSql, [
  118.             'productId' => $event->getProductId(),
  119.             'versionId' => Defaults::LIVE_VERSION,
  120.             'currentDate' => gmdate("Y-m-d H:i:s")
  121.         ]);
  122.         if (sizeof($bundleParentCheckResults) === || !isset($bundleParentCheckResults[0]['price'])) return;
  123.         $standardCustomerPriceRuleId '257e09ae47eb4823bdc0f59ed7ce242a';
  124.         $currencyId 'cb7d2554b0ce847cd82f3ac9bd1c0dfca';
  125.         $parentProductPrices json_decode($bundleParentCheckResults[0]['price'], true);
  126.         $parentProductPrice = isset($parentProductPrices[$currencyId]) ? $parentProductPrices[$currencyId] : null;
  127.         if (!$parentProductPrice) return;
  128.         $basePriceCalculatedEvent = new BasePriceCalculatedEvent($parentProductPrice$productId$standardCustomerPriceRuleId1$currencyIdfalse);
  129.         $this->calculateBundleChildrenSummaryPrice($basePriceCalculatedEvent);
  130.         $childrenSummaryPrice $basePriceCalculatedEvent->getPrice();
  131.         if ($parentProductPrice['gross'] !== $childrenSummaryPrice['gross'] || $parentProductPrice['net'] !== $childrenSummaryPrice['net']) {
  132.             $differenceNet $childrenSummaryPrice['net'] - $parentProductPrice['net'];
  133.             $parentProductPrice['gross'] = $childrenSummaryPrice['gross'];
  134.             $parentProductPrice['net'] = $childrenSummaryPrice['net'];
  135.             $parentProductPrices[$currencyId] = $parentProductPrice;
  136.             $this->productRepository->update([[
  137.                 'id' => $productId,
  138.                 'price' => $parentProductPrices
  139.             ]], $event->getContext());
  140.             if (!!$this->logger) {
  141.                 $this->logger->info('[BUNDLE PRICE] Bundle Parent Price was updated. Difference (net): ' $differenceNet ' P-ID: ' $productId ' New Price: ' json_encode($parentProductPrice));
  142.             }
  143.         }
  144.     }
  145. }