56 private $hasEntity =
null;
61 private $indexTableStructureFactory;
66 private $priceModifiers = [];
87 IndexTableStructureFactory $indexTableStructureFactory =
null,
88 array $priceModifiers = []
94 $this->indexTableStructureFactory = $indexTableStructureFactory ?:
96 foreach ($priceModifiers as $priceModifier) {
98 throw new \InvalidArgumentException(
99 'Argument \'priceModifiers\' must be of the type ' . PriceModifierInterface::class .
'[]' 103 $this->priceModifiers[] = $priceModifier;
124 $this->
_init(
'catalog_product_index_price',
'entity_id');
135 $this->_typeId = $typeCode;
147 if ($this->_typeId ===
null) {
148 throw new \Magento\Framework\Exception\LocalizedException(
149 __(
'A product type is not defined for the indexer.')
163 $this->_isComposite = (bool)$flag;
186 $this->tableStrategy->setUseIdxTable(
true);
216 if ($this->
hasEntity() || !empty($entityIds)) {
233 return $this->tableStrategy->getTableName(
'catalog_product_index_price_final');
254 private function prepareFinalPriceTable()
259 $finalPriceTable = $this->indexTableStructureFactory->create([
261 'entityField' =>
'entity_id',
262 'customerGroupField' =>
'customer_group_id',
263 'websiteField' =>
'website_id',
264 'taxClassField' =>
'tax_class_id',
265 'originalPriceField' =>
'orig_price',
266 'finalPriceField' =>
'price',
267 'minPriceField' =>
'min_price',
268 'maxPriceField' =>
'max_price',
269 'tierPriceField' =>
'tier_price',
272 return $finalPriceTable;
282 return $this->
getTable(
'catalog_product_index_website');
307 $finalPriceTable = $this->prepareFinalPriceTable();
310 $query =
$select->insertFromSelect($finalPriceTable->getTableName(), [],
false);
313 $this->modifyPriceIndex($finalPriceTable);
333 $linkField = $metadata->getLinkField();
336 [
'e' => $this->
getTable(
'catalog_product_entity')],
339 [
'cg' => $this->
getTable(
'customer_group')],
341 [
'customer_group_id']
343 [
'cw' => $this->
getTable(
'store_website')],
348 'cw.website_id = cwd.website_id',
351 [
'csg' => $this->
getTable(
'store_group')],
352 'csg.website_id = cw.website_id AND cw.default_group_id = csg.group_id',
356 'csg.default_store_id = cs.store_id AND cs.store_id != 0',
359 [
'pw' => $this->
getTable(
'catalog_product_website')],
360 'pw.product_id = e.entity_id AND pw.website_id = cw.website_id',
364 [
'tp' => $this->
getTable(
'catalog_product_index_tier_price')],
365 'tp.entity_id = e.entity_id AND tp.customer_group_id = cg.customer_group_id' .
366 ' AND tp.website_id = pw.website_id',
370 [
'tier_price_1' => $this->
getTable(
'catalog_product_entity_tier_price')],
371 'tier_price_1.' . $linkField .
' = e.' . $linkField .
' AND tier_price_1.all_groups = 0' .
372 ' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' .
373 ' AND tier_price_1.website_id = 0',
378 [
'tier_price_2' => $this->
getTable(
'catalog_product_entity_tier_price')],
379 'tier_price_2.' . $linkField .
' = e.' . $linkField .
' AND tier_price_2.all_groups = 0' .
380 ' AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' .
381 ' AND tier_price_2.website_id = cw.website_id',
385 [
'tier_price_3' => $this->
getTable(
'catalog_product_entity_tier_price')],
386 'tier_price_3.' . $linkField .
' = e.' . $linkField .
' AND tier_price_3.all_groups = 1' .
387 ' AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0',
391 [
'tier_price_4' => $this->
getTable(
'catalog_product_entity_tier_price')],
392 'tier_price_4.' . $linkField .
' = e.' . $linkField .
' AND tier_price_4.all_groups = 1' .
393 ' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' .
394 ' AND tier_price_4.website_id = cw.website_id',
398 if (
$type !==
null) {
415 if ($this->moduleManager->isEnabled(
'Magento_Tax')) {
423 $taxClassId = new \Zend_Db_Expr(
'0');
425 $select->columns([
'tax_class_id' => $taxClassId]);
451 $currentDate =
'cwd.website_date';
453 $maxUnsignedBigint =
'~0';
454 $specialFromDate =
$connection->getDatePartSql($specialFrom);
455 $specialToDate =
$connection->getDatePartSql($specialTo);
456 $specialFromExpr =
"{$specialFrom} IS NULL OR {$specialFromDate} <= {$currentDate}";
457 $specialToExpr =
"{$specialTo} IS NULL OR {$specialToDate} >= {$currentDate}";
459 "{$specialPrice} IS NOT NULL AND ({$specialFromExpr}) AND ({$specialToExpr})",
463 $tierPrice = $this->getTotalTierPriceExpression(
$price);
464 $tierPriceExpr =
$connection->getIfNullSql($tierPrice, $maxUnsignedBigint);
474 'price' =>
$connection->getIfNullSql($finalPrice, 0),
475 'min_price' =>
$connection->getIfNullSql($finalPrice, 0),
476 'max_price' =>
$connection->getIfNullSql($finalPrice, 0),
477 'tier_price' => $tierPrice,
478 'base_tier' => $tierPrice,
482 if ($entityIds !==
null) {
483 $select->where(
'e.entity_id IN(?)', $entityIds);
489 $this->_eventManager->dispatch(
490 'prepare_catalog_product_index_select',
509 return $this->tableStrategy->getTableName(
'catalog_product_index_price_opt_agr');
519 return $this->tableStrategy->getTableName(
'catalog_product_index_price_opt');
552 foreach ($this->priceModifiers as $priceModifier) {
553 $priceModifier->modifyPrice($finalPriceTable);
575 [
'i' => $finalPriceTable],
576 [
'entity_id',
'customer_group_id',
'website_id']
578 [
'e' => $this->
getTable(
'catalog_product_entity')],
579 'e.entity_id = i.entity_id',
582 [
'cw' => $this->
getTable(
'store_website')],
583 'cw.website_id = i.website_id',
586 [
'csg' => $this->
getTable(
'store_group')],
587 'csg.group_id = cw.default_group_id',
591 'cs.store_id = csg.default_store_id',
594 [
'o' => $this->
getTable(
'catalog_product_option')],
595 'o.product_id = e.' . $metadata->getLinkField(),
598 [
'ot' => $this->
getTable(
'catalog_product_option_type_value')],
599 'ot.option_id = o.option_id',
602 [
'otpd' => $this->
getTable(
'catalog_product_option_type_price')],
603 'otpd.option_type_id = ot.option_type_id AND otpd.store_id = 0',
606 [
'otps' => $this->
getTable(
'catalog_product_option_type_price')],
607 'otps.option_type_id = otpd.option_type_id AND otpd.store_id = cs.store_id',
610 [
'i.entity_id',
'i.customer_group_id',
'i.website_id',
'o.option_id']
613 $optPriceType =
$connection->getCheckSql(
'otps.option_type_price_id > 0',
'otps.price_type',
'otpd.price_type');
614 $optPriceValue =
$connection->getCheckSql(
'otps.option_type_price_id > 0',
'otps.price',
'otpd.price');
615 $minPriceRound = new \Zend_Db_Expr(
"ROUND(i.price * ({$optPriceValue} / 100), 4)");
616 $minPriceExpr =
$connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
617 $minPriceMin = new \Zend_Db_Expr(
"MIN({$minPriceExpr})");
618 $minPrice =
$connection->getCheckSql(
"MIN(o.is_require) = 1", $minPriceMin,
'0');
620 $tierPriceRound = new \Zend_Db_Expr(
"ROUND(i.base_tier * ({$optPriceValue} / 100), 4)");
621 $tierPriceExpr =
$connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
622 $tierPriceMin = new \Zend_Db_Expr(
"MIN({$tierPriceExpr})");
623 $tierPriceValue =
$connection->getCheckSql(
"MIN(o.is_require) > 0", $tierPriceMin, 0);
624 $tierPrice =
$connection->getCheckSql(
"MIN(i.base_tier) IS NOT NULL", $tierPriceValue,
"NULL");
626 $maxPriceRound = new \Zend_Db_Expr(
"ROUND(i.price * ({$optPriceValue} / 100), 4)");
627 $maxPriceExpr =
$connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $maxPriceRound);
629 "(MIN(o.type)='radio' OR MIN(o.type)='drop_down')",
630 "MAX({$maxPriceExpr})",
631 "SUM({$maxPriceExpr})" 636 'min_price' => $minPrice,
637 'max_price' => $maxPrice,
638 'tier_price' => $tierPrice,
646 [
'i' => $finalPriceTable],
647 [
'entity_id',
'customer_group_id',
'website_id']
649 [
'e' => $this->
getTable(
'catalog_product_entity')],
650 'e.entity_id = i.entity_id',
653 [
'cw' => $this->
getTable(
'store_website')],
654 'cw.website_id = i.website_id',
657 [
'csg' => $this->
getTable(
'store_group')],
658 'csg.group_id = cw.default_group_id',
662 'cs.store_id = csg.default_store_id',
665 [
'o' => $this->
getTable(
'catalog_product_option')],
666 'o.product_id = e.' . $metadata->getLinkField(),
669 [
'opd' => $this->
getTable(
'catalog_product_option_price')],
670 'opd.option_id = o.option_id AND opd.store_id = 0',
673 [
'ops' => $this->
getTable(
'catalog_product_option_price')],
674 'ops.option_id = opd.option_id AND ops.store_id = cs.store_id',
678 $optPriceType =
$connection->getCheckSql(
'ops.option_price_id > 0',
'ops.price_type',
'opd.price_type');
679 $optPriceValue =
$connection->getCheckSql(
'ops.option_price_id > 0',
'ops.price',
'opd.price');
681 $minPriceRound = new \Zend_Db_Expr(
"ROUND(i.price * ({$optPriceValue} / 100), 4)");
682 $priceExpr =
$connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
683 $minPrice =
$connection->getCheckSql(
"{$priceExpr} > 0 AND o.is_require = 1", $priceExpr, 0);
685 $maxPrice = $priceExpr;
687 $tierPriceRound = new \Zend_Db_Expr(
"ROUND(i.base_tier * ({$optPriceValue} / 100), 4)");
688 $tierPriceExpr =
$connection->getCheckSql(
"{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
689 $tierPriceValue =
$connection->getCheckSql(
"{$tierPriceExpr} > 0 AND o.is_require = 1", $tierPriceExpr, 0);
690 $tierPrice =
$connection->getCheckSql(
"i.base_tier IS NOT NULL", $tierPriceValue,
"NULL");
694 'min_price' => $minPrice,
695 'max_price' => $maxPrice,
696 'tier_price' => $tierPrice,
709 'min_price' =>
'SUM(min_price)',
710 'max_price' =>
'SUM(max_price)',
711 'tier_price' =>
'SUM(tier_price)',
714 [
'entity_id',
'customer_group_id',
'website_id']
719 $table = [
'i' => $finalPriceTable];
722 'i.entity_id = io.entity_id AND i.customer_group_id = io.customer_group_id' .
723 ' AND i.website_id = io.website_id',
728 'min_price' =>
new \
Zend_Db_Expr(
'i.min_price + io.min_price'),
729 'max_price' =>
new \
Zend_Db_Expr(
'i.max_price + io.max_price'),
731 'i.tier_price IS NOT NULL',
732 'i.tier_price + io.tier_price',
755 'entity_id' =>
'entity_id',
756 'customer_group_id' =>
'customer_group_id',
757 'website_id' =>
'website_id',
758 'tax_class_id' =>
'tax_class_id',
759 'price' =>
'orig_price',
760 'final_price' =>
'price',
761 'min_price' =>
'min_price',
762 'max_price' =>
'max_price',
763 'tier_price' =>
'tier_price',
770 if ($entityIds !==
null) {
771 $select->where(
'entity_id in (?)', count($entityIds) > 0 ? $entityIds : 0);
789 return $this->
getTable(
'catalog_product_index_tier_price');
801 return $this->tableStrategy->getTableName(
'catalog_product_index_price');
812 $select = $reader->select()->from(
813 [$this->
getTable(
'catalog_product_entity')],
822 return $this->hasEntity;
829 private function getTotalTierPriceExpression(\
Zend_Db_Expr $priceExpression)
831 $maxUnsignedBigint =
'~0';
837 'tier_price_1.value_id is NULL',
838 'tier_price_2.value_id is NULL',
839 'tier_price_3.value_id is NULL',
840 'tier_price_4.value_id is NULL' 846 $this->getTierPriceExpressionForTable(
'tier_price_1', $priceExpression),
850 $this->getTierPriceExpressionForTable(
'tier_price_2', $priceExpression),
854 $this->getTierPriceExpressionForTable(
'tier_price_3', $priceExpression),
858 $this->getTierPriceExpressionForTable(
'tier_price_4', $priceExpression),
870 private function getTierPriceExpressionForTable($tableAlias, \
Zend_Db_Expr $priceExpression)
873 sprintf(
'%s.value = 0', $tableAlias),
875 'ROUND(%s * (1 - ROUND(%s.percentage_value * cwd.rate, 4) / 100), 4)',
879 sprintf(
'ROUND(%s.value * cwd.rate, 4)', $tableAlias)
_getTierPriceIndexTable()
reindexEntity($entityIds)
_getCustomOptionAggregateTable()
_movePriceDataToIndexTable($entityIds=null)
_prepareCustomOptionAggregateTable()
_addAttributeToSelect($select, $attrCode, $entity, $store, $condition=null, $required=false)
_prepareDefaultFinalPriceTable()
_init($mainTable, $idFieldName)
__construct(\Magento\Framework\Model\ResourceModel\Db\Context $context, \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy, \Magento\Eav\Model\Config $eavConfig, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Framework\Module\Manager $moduleManager, $connectionName=null, IndexTableStructureFactory $indexTableStructureFactory=null, array $priceModifiers=[])
prepareFinalPriceDataForType($entityIds, $type)
_prepareCustomOptionPriceTable()
_prepareFinalPriceData($entityIds=null)
_getCustomOptionPriceTable()
getSelect($entityIds=null, $type=null)
_getDefaultFinalPriceTable()