Skip to content

Commit 8427030

Browse files
authored
Merge pull request #7781 from magento-l3/PR_22_JUL_2022_odubovyk
L3 Bugfix Delivery
2 parents 2e45de7 + 98068a6 commit 8427030

File tree

43 files changed

+1504
-413
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1504
-413
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Bundle\Test\Fixture;
9+
10+
use Magento\Bundle\Model\Product\Type;
11+
use Magento\Catalog\Api\ProductRepositoryInterface;
12+
use Magento\Framework\DataObject;
13+
use Magento\Framework\DataObjectFactory;
14+
use Magento\Quote\Api\CartRepositoryInterface;
15+
16+
class AddProductToCart extends \Magento\Quote\Test\Fixture\AddProductToCart
17+
{
18+
/**
19+
* @var ProductRepositoryInterface
20+
*/
21+
private ProductRepositoryInterface $productRepository;
22+
23+
/**
24+
* @var Type
25+
*/
26+
private Type $productType;
27+
28+
/**
29+
* @param CartRepositoryInterface $cartRepository
30+
* @param ProductRepositoryInterface $productRepository
31+
* @param DataObjectFactory $dataObjectFactory
32+
* @param Type $productType
33+
*/
34+
public function __construct(
35+
CartRepositoryInterface $cartRepository,
36+
ProductRepositoryInterface $productRepository,
37+
DataObjectFactory $dataObjectFactory,
38+
Type $productType
39+
) {
40+
parent::__construct($cartRepository, $productRepository, $dataObjectFactory);
41+
$this->productRepository = $productRepository;
42+
$this->productType = $productType;
43+
}
44+
45+
/**
46+
* {@inheritdoc}
47+
* @param array $data Parameters
48+
* $data['selections'] can be supplied in following formats:
49+
* - [["$product1.id$"], ["$product2.id$"]]
50+
* - [[{"product_id":"$product1.id$","qty":1}], [{"product_id":"$product2.id$","qty":1}]]
51+
* - To skip an option, pass empty array [["$product1.id$"], [], ["$product2.id$"]]
52+
* <pre>
53+
* $data = [
54+
* 'cart_id' => (int) Cart ID. Required.
55+
* 'product_id' => (int) Product ID. Required.
56+
* 'selections' => (array) array of options selections. Required.
57+
* 'qty' => (int) Quantity. Optional. Default: 1.
58+
* ]
59+
* </pre>
60+
*/
61+
public function apply(array $data = []): ?DataObject
62+
{
63+
$bundleProduct = $this->productRepository->getById($data['product_id']);
64+
$buyRequest = [
65+
'bundle_option' => [],
66+
'bundle_option_qty' => [],
67+
'qty' => $data['qty'] ?? 1,
68+
];
69+
$options = $this->productType->getOptionsCollection($bundleProduct);
70+
$selections = $this->productType->getSelectionsCollection([], $bundleProduct);
71+
$options->appendSelections($selections, true);
72+
$optionsList = array_values($options->getItems());
73+
foreach ($data['selections'] as $index => $selections) {
74+
if (!empty($selections)) {
75+
$option = $optionsList[$index];
76+
foreach ($selections as $item) {
77+
if (is_array($item)) {
78+
$productId = (int)$item['product_id'];
79+
$qty = $item['qty'] ?? 1;
80+
} else {
81+
$productId = (int)$item;
82+
$qty = 1;
83+
}
84+
foreach ($option->getSelections() as $selection) {
85+
if (((int)$selection->getProductId()) === $productId) {
86+
$buyRequest['bundle_option'][$option->getId()][] = $selection->getSelectionId();
87+
$buyRequest['bundle_option_qty'][$option->getId()][$selection->getSelectionId()] = $qty;
88+
break;
89+
}
90+
}
91+
}
92+
}
93+
}
94+
return parent::apply(
95+
[
96+
'cart_id' => $data['cart_id'],
97+
'product_id' => $data['product_id'],
98+
'buy_request' => $buyRequest
99+
]
100+
);
101+
}
102+
}

app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ abstract public function execute($ids);
170170
* @param array $processIds
171171
* @return AbstractAction
172172
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
173-
* @deprecated 102.0.6 Used only for backward compatibility for indexer, which not support indexation by dimensions
173+
* @deprecated 102.0.6
174+
* @see Used only for backward compatibility for indexer, which not support indexation by dimensions
174175
*/
175176
protected function _syncData(array $processIds = [])
176177
{
@@ -386,31 +387,33 @@ protected function _reindexRows($changedIds = [])
386387
$changedIds = array_unique(array_merge($changedIds, ...array_values($parentProductsTypes)));
387388
$productsTypes = array_merge_recursive($productsTypes, $parentProductsTypes);
388389

389-
if ($changedIds) {
390+
$typeIndexers = array_filter(
391+
$this->getTypeIndexers(),
392+
function ($type) use ($productsTypes) {
393+
return isset($productsTypes[$type]) && !empty($productsTypes[$type]);
394+
},
395+
ARRAY_FILTER_USE_KEY
396+
);
397+
if (empty($typeIndexers)) {
390398
$this->deleteIndexData($changedIds);
399+
return $changedIds;
391400
}
392401

393-
$typeIndexers = $this->getTypeIndexers();
394402
foreach ($typeIndexers as $productType => $indexer) {
395-
$entityIds = $productsTypes[$productType] ?? [];
396-
if (empty($entityIds)) {
397-
continue;
398-
}
399-
403+
$entityIds = $productsTypes[$productType];
400404
if ($indexer instanceof DimensionalIndexerInterface) {
401405
foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
402406
$this->tableMaintainer->createMainTmpTable($dimensions);
403407
$temporaryTable = $this->tableMaintainer->getMainTmpTable($dimensions);
404408
$this->_emptyTable($temporaryTable);
405409
$indexer->executeByDimensions($dimensions, \SplFixedArray::fromArray($entityIds, false));
406-
// copy to index
407-
$this->_insertFromTable(
408-
$temporaryTable,
409-
$this->tableMaintainer->getMainTableByDimensions($dimensions)
410-
);
410+
$mainTable = $this->tableMaintainer->getMainTableByDimensions($dimensions);
411+
$this->_insertFromTable($temporaryTable, $mainTable);
412+
$this->deleteOutdatedData($entityIds, $temporaryTable, $mainTable);
411413
}
412414
} else {
413415
// handle 3d-party indexers for backward compatibility
416+
$this->deleteIndexData($changedIds);
414417
$this->_emptyTable($this->_defaultIndexerResource->getIdxTable());
415418
$this->_copyRelationIndexData($entityIds);
416419
$indexer->reindexEntity($entityIds);
@@ -421,6 +424,30 @@ protected function _reindexRows($changedIds = [])
421424
return $changedIds;
422425
}
423426

427+
/**
428+
* Delete records that do not exist anymore
429+
*
430+
* @param array $entityIds
431+
* @param string $temporaryTable
432+
* @param string $mainTable
433+
* @return void
434+
*/
435+
private function deleteOutdatedData(array $entityIds, string $temporaryTable, string $mainTable): void
436+
{
437+
$joinCondition = [
438+
'tmp_table.entity_id = main_table.entity_id',
439+
'tmp_table.customer_group_id = main_table.customer_group_id',
440+
'tmp_table.website_id = main_table.website_id',
441+
];
442+
$select = $this->getConnection()->select()
443+
->from(['main_table' => $mainTable], null)
444+
->joinLeft(['tmp_table' => $temporaryTable], implode(' AND ', $joinCondition), null)
445+
->where('tmp_table.entity_id IS NULL')
446+
->where('main_table.entity_id IN (?)', $entityIds, \Zend_Db::INT_TYPE);
447+
$query = $select->deleteFromSelect('main_table');
448+
$this->getConnection()->query($query);
449+
}
450+
424451
/**
425452
* Delete Index data index for list of entities
426453
*
@@ -445,7 +472,8 @@ private function deleteIndexData(array $entityIds)
445472
* @param null|array $parentIds
446473
* @param array $excludeIds
447474
* @return \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
448-
* @deprecated 102.0.6 Used only for backward compatibility for do not broke custom indexer implementation
475+
* @deprecated 102.0.6
476+
* @see Used only for backward compatibility for do not broke custom indexer implementation
449477
* which do not work by dimensions.
450478
* For indexers, which support dimensions all composite products read data directly from main price indexer table
451479
* or replica table for partial or full reindex correspondingly.

app/code/Magento/Catalog/Model/Product/Price/TierPriceFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ public function create(array $rawPrice, $sku)
9595
$price->setCustomerGroup(
9696
$rawPrice['all_groups'] == $this->allGroupsId
9797
? $this->allGroupsValue
98-
: $this->customerGroupRepository->getById($rawPrice['customer_group_id'])->getCode()
98+
: ($rawPrice['customer_group_code']
99+
?? $this->customerGroupRepository->getById($rawPrice['customer_group_id'])->getCode())
99100
);
100101
$price->setQuantity($rawPrice['qty']);
101102

app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Magento\Catalog\Model\Indexer\Product\Price\Processor as PriceIndexerProcessor;
1212
use Magento\Catalog\Model\Product\Price\Validation\TierPriceValidator;
1313
use Magento\Catalog\Model\ProductIdLocatorInterface;
14+
use Magento\Customer\Model\ResourceModel\Group\GetCustomerGroupCodesByIds;
1415

1516
class TierPriceStorage implements TierPriceStorageInterface
1617
{
@@ -22,8 +23,6 @@ class TierPriceStorage implements TierPriceStorageInterface
2223
private $tierPricePersistence;
2324

2425
/**
25-
* Tier price validator.
26-
*
2726
* @var TierPriceValidator
2827
*/
2928
private $tierPriceValidator;
@@ -36,38 +35,42 @@ class TierPriceStorage implements TierPriceStorageInterface
3635
private $tierPriceFactory;
3736

3837
/**
39-
* Price index processor.
40-
*
4138
* @var PriceIndexerProcessor
4239
*/
4340
private $priceIndexProcessor;
4441

4542
/**
46-
* Product ID locator.
47-
*
4843
* @var ProductIdLocatorInterface
4944
*/
5045
private $productIdLocator;
5146

47+
/**
48+
* @var GetCustomerGroupCodesByIds
49+
*/
50+
private $getCustomerGroupCodesByIds;
51+
5252
/**
5353
* @param TierPricePersistence $tierPricePersistence
5454
* @param TierPriceValidator $tierPriceValidator
5555
* @param TierPriceFactory $tierPriceFactory
5656
* @param PriceIndexerProcessor $priceIndexProcessor
5757
* @param ProductIdLocatorInterface $productIdLocator
58+
* @param GetCustomerGroupCodesByIds $getCustomerGroupCodesByIds
5859
*/
5960
public function __construct(
6061
TierPricePersistence $tierPricePersistence,
6162
TierPriceValidator $tierPriceValidator,
6263
TierPriceFactory $tierPriceFactory,
6364
PriceIndexerProcessor $priceIndexProcessor,
64-
ProductIdLocatorInterface $productIdLocator
65+
ProductIdLocatorInterface $productIdLocator,
66+
GetCustomerGroupCodesByIds $getCustomerGroupCodesByIds
6567
) {
6668
$this->tierPricePersistence = $tierPricePersistence;
6769
$this->tierPriceValidator = $tierPriceValidator;
6870
$this->tierPriceFactory = $tierPriceFactory;
6971
$this->priceIndexProcessor = $priceIndexProcessor;
7072
$this->productIdLocator = $productIdLocator;
73+
$this->getCustomerGroupCodesByIds = $getCustomerGroupCodesByIds;
7174
}
7275

7376
/**
@@ -148,8 +151,22 @@ private function getExistingPrices(array $skus, bool $groupBySku = false): array
148151
if ($rawPrices) {
149152
$linkField = $this->tierPricePersistence->getEntityLinkField();
150153
$skuByIdLookup = $this->buildSkuByIdLookup($skus);
154+
$customerGroupCodesByIds = $this->getCustomerGroupCodesByIds->execute(
155+
array_column(
156+
array_filter(
157+
$rawPrices,
158+
static function (array $row) {
159+
return (int) $row['all_groups'] !== 1;
160+
}
161+
),
162+
'customer_group_id'
163+
),
164+
);
151165
foreach ($rawPrices as $rawPrice) {
152166
$sku = $skuByIdLookup[$rawPrice[$linkField]];
167+
if (isset($customerGroupCodesByIds[$rawPrice['customer_group_id']])) {
168+
$rawPrice['customer_group_code'] = $customerGroupCodesByIds[$rawPrice['customer_group_id']];
169+
}
153170
$price = $this->tierPriceFactory->create($rawPrice, $sku);
154171
if ($groupBySku) {
155172
$prices[$sku][] = $price;

0 commit comments

Comments
 (0)