Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
BaseFinalPrice.php
Go to the documentation of this file.
1 <?php
6 declare(strict_types=1);
7 
9 
16 
22 {
26  private $resource;
27 
31  private $connectionName;
32 
36  private $joinAttributeProcessor;
37 
41  private $moduleManager;
42 
46  private $eventManager;
47 
53  private $dimensionToFieldMapper = [
54  WebsiteDimensionProvider::DIMENSION_NAME => 'pw.website_id',
55  CustomerGroupDimensionProvider::DIMENSION_NAME => 'cg.customer_group_id',
56  ];
57 
61  private $connection;
62 
66  private $metadataPool;
67 
75  public function __construct(
76  \Magento\Framework\App\ResourceConnection $resource,
77  JoinAttributeProcessor $joinAttributeProcessor,
78  \Magento\Framework\Module\Manager $moduleManager,
79  \Magento\Framework\Event\ManagerInterface $eventManager,
80  \Magento\Framework\EntityManager\MetadataPool $metadataPool,
81  $connectionName = 'indexer'
82  ) {
83  $this->resource = $resource;
84  $this->connectionName = $connectionName;
85  $this->joinAttributeProcessor = $joinAttributeProcessor;
86  $this->moduleManager = $moduleManager;
87  $this->eventManager = $eventManager;
88  $this->metadataPool = $metadataPool;
89  }
90 
101  public function getQuery(array $dimensions, string $productType, array $entityIds = []): Select
102  {
103  $connection = $this->getConnection();
104  $metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
105  $linkField = $metadata->getLinkField();
106 
107  $select = $connection->select()->from(
108  ['e' => $this->getTable('catalog_product_entity')],
109  ['entity_id']
110  )->joinInner(
111  ['cg' => $this->getTable('customer_group')],
112  array_key_exists(CustomerGroupDimensionProvider::DIMENSION_NAME, $dimensions)
113  ? sprintf(
114  '%s = %s',
115  $this->dimensionToFieldMapper[CustomerGroupDimensionProvider::DIMENSION_NAME],
116  $dimensions[CustomerGroupDimensionProvider::DIMENSION_NAME]->getValue()
117  ) : '',
118  ['customer_group_id']
119  )->joinInner(
120  ['pw' => $this->getTable('catalog_product_website')],
121  'pw.product_id = e.entity_id',
122  ['pw.website_id']
123  )->joinInner(
124  ['cwd' => $this->getTable('catalog_product_index_website')],
125  'pw.website_id = cwd.website_id',
126  []
127  )->joinLeft(
128  // we need this only for BCC in case someone expects table `tp` to be present in query
129  ['tp' => $this->getTable('catalog_product_index_tier_price')],
130  'tp.entity_id = e.entity_id AND' .
131  ' tp.customer_group_id = cg.customer_group_id AND tp.website_id = pw.website_id',
132  []
133  )->joinLeft(
134  // calculate tier price specified as Website = `All Websites` and Customer Group = `Specific Customer Group`
135  ['tier_price_1' => $this->getTable('catalog_product_entity_tier_price')],
136  'tier_price_1.' . $linkField . ' = e.' . $linkField . ' AND tier_price_1.all_groups = 0' .
137  ' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' .
138  ' AND tier_price_1.website_id = 0',
139  []
140  )->joinLeft(
141  // calculate tier price specified as Website = `Specific Website`
142  //and Customer Group = `Specific Customer Group`
143  ['tier_price_2' => $this->getTable('catalog_product_entity_tier_price')],
144  'tier_price_2.' . $linkField . ' = e.' . $linkField . ' AND tier_price_2.all_groups = 0 ' .
145  'AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' .
146  ' AND tier_price_2.website_id = pw.website_id',
147  []
148  )->joinLeft(
149  // calculate tier price specified as Website = `All Websites` and Customer Group = `ALL GROUPS`
150  ['tier_price_3' => $this->getTable('catalog_product_entity_tier_price')],
151  'tier_price_3.' . $linkField . ' = e.' . $linkField . ' AND tier_price_3.all_groups = 1 ' .
152  'AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0',
153  []
154  )->joinLeft(
155  // calculate tier price specified as Website = `Specific Website` and Customer Group = `ALL GROUPS`
156  ['tier_price_4' => $this->getTable('catalog_product_entity_tier_price')],
157  'tier_price_4.' . $linkField . ' = e.' . $linkField . ' AND tier_price_4.all_groups = 1' .
158  ' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' .
159  ' AND tier_price_4.website_id = pw.website_id',
160  []
161  );
162 
163  foreach ($dimensions as $dimension) {
164  if (!isset($this->dimensionToFieldMapper[$dimension->getName()])) {
165  throw new \LogicException(
166  'Provided dimension is not valid for Price indexer: ' . $dimension->getName()
167  );
168  }
169  $select->where($this->dimensionToFieldMapper[$dimension->getName()] . ' = ?', $dimension->getValue());
170  }
171 
172  if ($this->moduleManager->isEnabled('Magento_Tax')) {
173  $taxClassId = $this->joinAttributeProcessor->process($select, 'tax_class_id');
174  } else {
175  $taxClassId = new \Zend_Db_Expr(0);
176  }
177  $select->columns(['tax_class_id' => $taxClassId]);
178 
179  $this->joinAttributeProcessor->process($select, 'status', Status::STATUS_ENABLED);
180 
181  $price = $this->joinAttributeProcessor->process($select, 'price');
182  $specialPrice = $this->joinAttributeProcessor->process($select, 'special_price');
183  $specialFrom = $this->joinAttributeProcessor->process($select, 'special_from_date');
184  $specialTo = $this->joinAttributeProcessor->process($select, 'special_to_date');
185  $currentDate = 'cwd.website_date';
186 
187  $maxUnsignedBigint = '~0';
188  $specialFromDate = $connection->getDatePartSql($specialFrom);
189  $specialToDate = $connection->getDatePartSql($specialTo);
190  $specialFromExpr = "{$specialFrom} IS NULL OR {$specialFromDate} <= {$currentDate}";
191  $specialToExpr = "{$specialTo} IS NULL OR {$specialToDate} >= {$currentDate}";
192  $specialPriceExpr = $connection->getCheckSql(
193  "{$specialPrice} IS NOT NULL AND ({$specialFromExpr}) AND ({$specialToExpr})",
194  $specialPrice,
195  $maxUnsignedBigint
196  );
197  $tierPrice = $this->getTotalTierPriceExpression($price);
198  $tierPriceExpr = $connection->getIfNullSql($tierPrice, $maxUnsignedBigint);
199  $finalPrice = $connection->getLeastSql([
200  $price,
201  $specialPriceExpr,
202  $tierPriceExpr,
203  ]);
204 
205  $select->columns(
206  [
207  //orig_price in catalog_product_index_price_final_tmp
208  'price' => $connection->getIfNullSql($price, 0),
209  //price in catalog_product_index_price_final_tmp
210  'final_price' => $connection->getIfNullSql($finalPrice, 0),
211  'min_price' => $connection->getIfNullSql($finalPrice, 0),
212  'max_price' => $connection->getIfNullSql($finalPrice, 0),
213  'tier_price' => $tierPrice,
214  ]
215  );
216 
217  $select->where("e.type_id = ?", $productType);
218 
219  if ($entityIds !== null) {
220  if (count($entityIds) > 1) {
221  $select->where(sprintf('e.entity_id BETWEEN %s AND %s', min($entityIds), max($entityIds)));
222  } else {
223  $select->where('e.entity_id = ?', $entityIds);
224  }
225  }
226 
230  $this->eventManager->dispatch(
231  'prepare_catalog_product_index_select',
232  [
233  'select' => $select,
234  'entity_field' => new ColumnValueExpression('e.entity_id'),
235  'website_field' => new ColumnValueExpression('pw.website_id'),
236  'store_field' => new ColumnValueExpression('cwd.default_store_id'),
237  ]
238  );
239 
240  return $select;
241  }
242 
249  private function getTotalTierPriceExpression(\Zend_Db_Expr $priceExpression)
250  {
251  $maxUnsignedBigint = '~0';
252 
253  return $this->getConnection()->getCheckSql(
254  implode(
255  ' AND ',
256  [
257  'tier_price_1.value_id is NULL',
258  'tier_price_2.value_id is NULL',
259  'tier_price_3.value_id is NULL',
260  'tier_price_4.value_id is NULL'
261  ]
262  ),
263  'NULL',
264  $this->getConnection()->getLeastSql([
265  $this->getConnection()->getIfNullSql(
266  $this->getTierPriceExpressionForTable('tier_price_1', $priceExpression),
267  $maxUnsignedBigint
268  ),
269  $this->getConnection()->getIfNullSql(
270  $this->getTierPriceExpressionForTable('tier_price_2', $priceExpression),
271  $maxUnsignedBigint
272  ),
273  $this->getConnection()->getIfNullSql(
274  $this->getTierPriceExpressionForTable('tier_price_3', $priceExpression),
275  $maxUnsignedBigint
276  ),
277  $this->getConnection()->getIfNullSql(
278  $this->getTierPriceExpressionForTable('tier_price_4', $priceExpression),
279  $maxUnsignedBigint
280  ),
281  ])
282  );
283  }
284 
292  private function getTierPriceExpressionForTable($tableAlias, \Zend_Db_Expr $priceExpression): \Zend_Db_Expr
293  {
294  return $this->getConnection()->getCheckSql(
295  sprintf('%s.value = 0', $tableAlias),
296  sprintf(
297  'ROUND(%s * (1 - ROUND(%s.percentage_value * cwd.rate, 4) / 100), 4)',
298  $priceExpression,
299  $tableAlias
300  ),
301  sprintf('ROUND(%s.value * cwd.rate, 4)', $tableAlias)
302  );
303  }
304 
311  private function getConnection(): \Magento\Framework\DB\Adapter\AdapterInterface
312  {
313  if ($this->connection === null) {
314  $this->connection = $this->resource->getConnection($this->connectionName);
315  }
316 
317  return $this->connection;
318  }
319 
326  private function getTable($tableName)
327  {
328  return $this->resource->getTableName($tableName, $this->connectionName);
329  }
330 }
$tableName
Definition: trigger.php:13
__construct(\Magento\Framework\App\ResourceConnection $resource, JoinAttributeProcessor $joinAttributeProcessor, \Magento\Framework\Module\Manager $moduleManager, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Framework\EntityManager\MetadataPool $metadataPool, $connectionName='indexer')
$resource
Definition: bulk.php:12
$price
getQuery(array $dimensions, string $productType, array $entityIds=[])
$moduleManager
Definition: products.php:75