diff -Nuar a/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Price.php b/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Price.php index 077ebd4422a..a2fff5739f2 100644 --- a/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Price.php +++ b/vendor/magento/module-bundle/Model/ResourceModel/Indexer/Price.php @@ -7,6 +7,7 @@ namespace Magento\Bundle\Model\ResourceModel\Indexer; use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BasePriceModifier; +use Magento\Framework\DB\Select; use Magento\Framework\Indexer\DimensionalIndexerInterface; use Magento\Framework\EntityManager\MetadataPool; use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer; @@ -394,8 +395,8 @@ class Price implements DimensionalIndexerInterface $connection = $this->getConnection(); $this->prepareBundleSelectionTable(); - $this->calculateBundleSelectionPrice($dimensions, \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED); - $this->calculateBundleSelectionPrice($dimensions, \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC); + $this->calculateFixedBundleSelectionPrice(); + $this->calculateDynamicBundleSelectionPrice($dimensions); $this->prepareBundleOptionTable(); @@ -426,84 +427,17 @@ class Price implements DimensionalIndexerInterface } /** - * Calculate bundle product selections price by product type + * Get base select for bundle selection price * - * @param array $dimensions - * @param int $priceType - * @return void + * @return Select * @throws \Exception - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - private function calculateBundleSelectionPrice($dimensions, $priceType) + private function getBaseBundleSelectionPriceSelect(): Select { - $connection = $this->getConnection(); - - if ($priceType == \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED) { - $selectionPriceValue = $connection->getCheckSql( - 'bsp.selection_price_value IS NULL', - 'bs.selection_price_value', - 'bsp.selection_price_value' - ); - $selectionPriceType = $connection->getCheckSql( - 'bsp.selection_price_type IS NULL', - 'bs.selection_price_type', - 'bsp.selection_price_type' - ); - $priceExpr = new \Zend_Db_Expr( - $connection->getCheckSql( - $selectionPriceType . ' = 1', - 'ROUND(i.price * (' . $selectionPriceValue . ' / 100),4)', - $connection->getCheckSql( - 'i.special_price > 0 AND i.special_price < 100', - 'ROUND(' . $selectionPriceValue . ' * (i.special_price / 100),4)', - $selectionPriceValue - ) - ) . '* bs.selection_qty' - ); - - $tierExpr = $connection->getCheckSql( - 'i.base_tier IS NOT NULL', - $connection->getCheckSql( - $selectionPriceType . ' = 1', - 'ROUND(i.base_tier - (i.base_tier * (' . $selectionPriceValue . ' / 100)),4)', - $connection->getCheckSql( - 'i.tier_percent > 0', - 'ROUND((1 - i.tier_percent / 100) * ' . $selectionPriceValue . ',4)', - $selectionPriceValue - ) - ) . ' * bs.selection_qty', - 'NULL' - ); - - $priceExpr = $connection->getLeastSql( - [ - $priceExpr, - $connection->getIfNullSql($tierExpr, $priceExpr), - ] - ); - } else { - $price = 'idx.min_price * bs.selection_qty'; - $specialExpr = $connection->getCheckSql( - 'i.special_price > 0 AND i.special_price < 100', - 'ROUND(' . $price . ' * (i.special_price / 100), 4)', - $price - ); - $tierExpr = $connection->getCheckSql( - 'i.tier_percent IS NOT NULL', - 'ROUND((1 - i.tier_percent / 100) * ' . $price . ', 4)', - 'NULL' - ); - $priceExpr = $connection->getLeastSql( - [ - $specialExpr, - $connection->getIfNullSql($tierExpr, $price), - ] - ); - } - $metadata = $this->metadataPool->getMetadata(ProductInterface::class); $linkField = $metadata->getLinkField(); - $select = $connection->select()->from( + + $select = $this->getConnection()->select()->from( ['i' => $this->getBundlePriceTable()], ['entity_id', 'customer_group_id', 'website_id'] )->join( @@ -518,22 +452,173 @@ class Price implements DimensionalIndexerInterface ['bs' => $this->getTable('catalog_product_bundle_selection')], 'bs.option_id = bo.option_id', ['selection_id'] - )->joinLeft( + ); + + return $select; + } + + /** + * Apply selections price for fixed bundles + * + * @return void + * @throws \Exception + */ + private function applyFixedBundleSelectionPrice() + { + $connection = $this->getConnection(); + + $selectionPriceValue = 'bsp.selection_price_value'; + $selectionPriceType = 'bsp.selection_price_type'; + $priceExpr = new \Zend_Db_Expr( + $connection->getCheckSql( + $selectionPriceType . ' = 1', + 'ROUND(i.price * (' . $selectionPriceValue . ' / 100),4)', + $connection->getCheckSql( + 'i.special_price > 0 AND i.special_price < 100', + 'ROUND(' . $selectionPriceValue . ' * (i.special_price / 100),4)', + $selectionPriceValue + ) + ) . '* bs.selection_qty' + ); + $tierExpr = $connection->getCheckSql( + 'i.base_tier IS NOT NULL', + $connection->getCheckSql( + $selectionPriceType . ' = 1', + 'ROUND(i.base_tier - (i.base_tier * (' . $selectionPriceValue . ' / 100)),4)', + $connection->getCheckSql( + 'i.tier_percent > 0', + 'ROUND((1 - i.tier_percent / 100) * ' . $selectionPriceValue . ',4)', + $selectionPriceValue + ) + ) . ' * bs.selection_qty', + 'NULL' + ); + $priceExpr = $connection->getLeastSql( + [ + $priceExpr, + $connection->getIfNullSql($tierExpr, $priceExpr), + ] + ); + + $select = $this->getBaseBundleSelectionPriceSelect(); + $select->joinInner( ['bsp' => $this->getTable('catalog_product_bundle_selection_price')], 'bs.selection_id = bsp.selection_id AND bsp.website_id = i.website_id', - [''] - )->join( + [] + )->where( + 'i.price_type=?', + \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED + )->columns( + [ + 'group_type' => $connection->getCheckSql("bo.type = 'select' OR bo.type = 'radio'", '0', '1'), + 'is_required' => 'bo.required', + 'price' => $priceExpr, + 'tier_price' => $tierExpr, + ] + ); + $query = $select->crossUpdateFromSelect($this->getBundleSelectionTable()); + $connection->query($query); + } + + /** + * Calculate selections price for fixed bundles + * + * @return void + * @throws \Exception + */ + private function calculateFixedBundleSelectionPrice() + { + $connection = $this->getConnection(); + + $selectionPriceValue = 'bs.selection_price_value'; + $selectionPriceType = 'bs.selection_price_type'; + $priceExpr = new \Zend_Db_Expr( + $connection->getCheckSql( + $selectionPriceType . ' = 1', + 'ROUND(i.price * (' . $selectionPriceValue . ' / 100),4)', + $connection->getCheckSql( + 'i.special_price > 0 AND i.special_price < 100', + 'ROUND(' . $selectionPriceValue . ' * (i.special_price / 100),4)', + $selectionPriceValue + ) + ) . '* bs.selection_qty' + ); + $tierExpr = $connection->getCheckSql( + 'i.base_tier IS NOT NULL', + $connection->getCheckSql( + $selectionPriceType . ' = 1', + 'ROUND(i.base_tier - (i.base_tier * (' . $selectionPriceValue . ' / 100)),4)', + $connection->getCheckSql( + 'i.tier_percent > 0', + 'ROUND((1 - i.tier_percent / 100) * ' . $selectionPriceValue . ',4)', + $selectionPriceValue + ) + ) . ' * bs.selection_qty', + 'NULL' + ); + $priceExpr = $connection->getLeastSql( + [ + $priceExpr, + $connection->getIfNullSql($tierExpr, $priceExpr), + ] + ); + + $select = $this->getBaseBundleSelectionPriceSelect(); + $select->where( + 'i.price_type=?', + \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED + )->columns( + [ + 'group_type' => $connection->getCheckSql("bo.type = 'select' OR bo.type = 'radio'", '0', '1'), + 'is_required' => 'bo.required', + 'price' => $priceExpr, + 'tier_price' => $tierExpr, + ] + ); + $query = $select->insertFromSelect($this->getBundleSelectionTable()); + $connection->query($query); + + $this->applyFixedBundleSelectionPrice(); + } + + /** + * Calculate selections price for dynamic bundles + * + * @param array $dimensions + * @return void + * @throws \Exception + */ + private function calculateDynamicBundleSelectionPrice($dimensions) + { + $connection = $this->getConnection(); + + $price = 'idx.min_price * bs.selection_qty'; + $specialExpr = $connection->getCheckSql( + 'i.special_price > 0 AND i.special_price < 100', + 'ROUND(' . $price . ' * (i.special_price / 100), 4)', + $price + ); + $tierExpr = $connection->getCheckSql( + 'i.tier_percent IS NOT NULL', + 'ROUND((1 - i.tier_percent / 100) * ' . $price . ', 4)', + 'NULL' + ); + $priceExpr = $connection->getLeastSql( + [ + $specialExpr, + $connection->getIfNullSql($tierExpr, $price), + ] + ); + + $select = $this->getBaseBundleSelectionPriceSelect(); + $select->join( ['idx' => $this->getMainTable($dimensions)], 'bs.product_id = idx.entity_id AND i.customer_group_id = idx.customer_group_id' . ' AND i.website_id = idx.website_id', [] - )->join( - ['e' => $this->getTable('catalog_product_entity')], - 'bs.product_id = e.entity_id AND e.required_options=0', - [] )->where( 'i.price_type=?', - $priceType + \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC )->columns( [ 'group_type' => $connection->getCheckSql("bo.type = 'select' OR bo.type = 'radio'", '0', '1'), @@ -542,7 +627,6 @@ class Price implements DimensionalIndexerInterface 'tier_price' => $tierExpr, ] ); - $query = $select->insertFromSelect($this->getBundleSelectionTable()); $connection->query($query); }