Skip to content

Commit 94cc576

Browse files
authored
Merge branch '2.4-develop' into ramsey-uuid
2 parents d9178a4 + 94f5b99 commit 94cc576

File tree

28 files changed

+6707
-5607
lines changed

28 files changed

+6707
-5607
lines changed

app/code/Magento/Catalog/Model/Product/Option/Repository.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ public function save(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $opt
158158
$option->setData('product_id', $product->getData($metadata->getLinkField()));
159159
$option->setData('store_id', $product->getStoreId());
160160

161+
$backedOptions = $option->getValues();
161162
if ($option->getOptionId()) {
162163
$options = $product->getOptions();
163164
if (!$options) {
@@ -174,6 +175,9 @@ public function save(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $opt
174175
}
175176
$originalValues = $persistedOption->getValues();
176177
$newValues = $option->getData('values');
178+
if (!$newValues) {
179+
$newValues = $this->getOptionValues($option);
180+
}
177181
if ($newValues) {
178182
if (isset($originalValues)) {
179183
$newValues = $this->markRemovedValues($newValues, $originalValues);
@@ -182,6 +186,8 @@ public function save(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $opt
182186
}
183187
}
184188
$option->save();
189+
// Required for API response data consistency
190+
$option->setValues($backedOptions);
185191
return $option;
186192
}
187193

@@ -249,4 +255,28 @@ private function getHydratorPool()
249255
}
250256
return $this->hydratorPool;
251257
}
258+
259+
/**
260+
* Get Option values from property
261+
*
262+
* Gets Option values stored in property, modifies for needed format and clears the property
263+
*
264+
* @param \Magento\Catalog\Api\Data\ProductCustomOptionInterface $option
265+
* @return array|null
266+
*/
267+
private function getOptionValues(\Magento\Catalog\Api\Data\ProductCustomOptionInterface $option): ?array
268+
{
269+
if ($option->getValues() === null) {
270+
return null;
271+
}
272+
273+
$optionValues = [];
274+
275+
foreach ($option->getValues() as $optionValue) {
276+
$optionValues[] = $optionValue->getData();
277+
}
278+
$option->setValues(null);
279+
280+
return $optionValues;
281+
}
252282
}

app/code/Magento/Catalog/Model/Product/Type.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ public function factory($product)
127127

128128
$typeModel = $this->_productTypePool->get($typeModelName);
129129
$typeModel->setConfig($types[$typeId]);
130+
$typeModel->setTypeId($typeId);
131+
130132
return $typeModel;
131133
}
132134

app/code/Magento/Catalog/Model/Product/Type/AbstractType.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,9 @@ protected function _removeNotApplicableAttributes($product)
752752
*/
753753
public function beforeSave($product)
754754
{
755+
if (!$product->getTypeId()) {
756+
$product->setTypeId($this->_typeId);
757+
}
755758
$this->_removeNotApplicableAttributes($product);
756759
$product->canAffectOptions(true);
757760
return $this;

app/code/Magento/Catalog/Model/ProductIdLocator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public function retrieveProductIdsBySkus(array $skus)
124124
private function truncateToLimit()
125125
{
126126
if (count($this->idsBySku) > $this->idsLimit) {
127-
$this->idsBySku = array_slice($this->idsBySku, round($this->idsLimit / -2));
127+
$this->idsBySku = array_slice($this->idsBySku, $this->idsLimit * -1, null, true);
128128
}
129129
}
130130
}

app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleSetEditRelatedProductsTest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<conditionalClick selector="{{AdminProductFormRelatedUpSellCrossSellSection.relatedDropdown}}" dependentSelector="{{AdminProductFormRelatedUpSellCrossSellSection.relatedDependent}}" visible="false" stepKey="openDropDownIfClosedRelatedSee2"/>
101101
<see selector="{{AdminProductFormRelatedUpSellCrossSellSection.selectedRelatedProduct}}" userInput="$$simpleProduct6.name$$" stepKey="seeSixthRelatedProduct"/>
102102
<selectOption selector=".admin__collapsible-block-wrapper[data-index='related'] .admin__control-select" userInput="5" stepKey="selectFivePerPage"/>
103+
<waitForPageLoad stepKey="waitForLoadingAfterSelectFivePerPage"/>
103104
<dontSee selector="{{AdminProductFormRelatedUpSellCrossSellSection.selectedRelatedProduct}}" userInput="$$simpleProduct6.name$$" stepKey="dontSeeSixthRelatedProduct"/>
104105

105106
<!--See related product in storefront-->

app/code/Magento/Catalog/Test/Unit/Model/Product/Option/RepositoryTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ public function testSave()
262262
->getMock();
263263
$optionCollection->expects($this->once())->method('getProductOptions')->willReturn([$this->optionMock]);
264264
$this->optionCollectionFactory->expects($this->once())->method('create')->willReturn($optionCollection);
265-
$this->optionMock->expects($this->once())->method('getValues')->willReturn([
265+
$this->optionMock->expects($this->exactly(2))->method('getValues')->willReturn([
266266
$originalValue1,
267267
$originalValue2,
268268
$originalValue3
@@ -291,7 +291,7 @@ public function testSaveWhenOptionTypeWasChanged()
291291
->getMock();
292292
$optionCollection->expects($this->once())->method('getProductOptions')->willReturn([$this->optionMock]);
293293
$this->optionCollectionFactory->expects($this->once())->method('create')->willReturn($optionCollection);
294-
$this->optionMock->expects($this->once())->method('getValues')->willReturn(null);
294+
$this->optionMock->expects($this->exactly(2))->method('getValues')->willReturn(null);
295295
$this->assertEquals($this->optionMock, $this->optionRepository->save($this->optionMock));
296296
}
297297
}

app/code/Magento/Catalog/Test/Unit/Model/ProductIdLocatorTest.php

Lines changed: 109 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
1414
use Magento\Framework\EntityManager\EntityMetadataInterface;
1515
use Magento\Framework\EntityManager\MetadataPool;
16-
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
1716
use PHPUnit\Framework\MockObject\MockObject;
1817
use PHPUnit\Framework\TestCase;
1918

@@ -23,94 +22,145 @@
2322
class ProductIdLocatorTest extends TestCase
2423
{
2524
/**
26-
* @var MetadataPool|MockObject
25+
* @var int
2726
*/
28-
private $metadataPool;
27+
private $idsLimit;
2928

3029
/**
31-
* @var CollectionFactory|MockObject
30+
* @var string
3231
*/
33-
private $collectionFactory;
32+
private $linkField;
33+
34+
/**
35+
* @var Collection|MockObject
36+
*/
37+
private $collection;
3438

3539
/**
3640
* @var ProductIdLocator
3741
*/
3842
private $model;
3943

4044
/**
41-
* Set up.
42-
*
43-
* @return void
45+
* @inheritDoc
4446
*/
4547
protected function setUp(): void
4648
{
47-
$this->metadataPool = $this->getMockBuilder(MetadataPool::class)
48-
->setMethods(['getMetadata'])
49-
->disableOriginalConstructor()
50-
->getMock();
51-
$this->collectionFactory = $this
52-
->getMockBuilder(CollectionFactory::class)
49+
$metadataPool = $this->createMock(MetadataPool::class);
50+
$collectionFactory = $this->getMockBuilder(CollectionFactory::class)
5351
->setMethods(['create'])
5452
->disableOriginalConstructor()
5553
->getMock();
54+
$this->idsLimit = 4;
5655

57-
$objectManager = new ObjectManager($this);
58-
$this->model = $objectManager->getObject(
59-
ProductIdLocator::class,
60-
[
61-
'metadataPool' => $this->metadataPool,
62-
'collectionFactory' => $this->collectionFactory,
63-
]
64-
);
56+
$this->linkField = 'entity_id';
57+
$metaDataInterface = $this->createMock(EntityMetadataInterface::class);
58+
$metaDataInterface->method('getLinkField')
59+
->willReturn($this->linkField);
60+
$metadataPool->method('getMetadata')
61+
->with(ProductInterface::class)
62+
->willReturn($metaDataInterface);
63+
64+
$this->collection = $this->createMock(Collection::class);
65+
$collectionFactory->method('create')
66+
->willReturn($this->collection);
67+
68+
$this->model = new ProductIdLocator($metadataPool, $collectionFactory, $this->idsLimit);
6569
}
6670

67-
/**
68-
* Test retrieve
69-
*/
7071
public function testRetrieveProductIdsBySkus()
7172
{
7273
$skus = ['sku_1', 'sku_2'];
73-
$collection = $this->getMockBuilder(Collection::class)
74-
->setMethods(
75-
[
76-
'getItems',
77-
'addFieldToFilter',
78-
'setPageSize',
79-
'getLastPageNumber',
80-
'setCurPage',
81-
'clear'
82-
]
83-
)
84-
->disableOriginalConstructor()
85-
->getMock();
74+
8675
$product = $this->getMockBuilder(ProductInterface::class)
8776
->setMethods(['getSku', 'getData', 'getTypeId'])
8877
->disableOriginalConstructor()
8978
->getMockForAbstractClass();
90-
$metaDataInterface = $this->getMockBuilder(EntityMetadataInterface::class)
91-
->setMethods(['getLinkField'])
92-
->disableOriginalConstructor()
93-
->getMockForAbstractClass();
94-
$this->collectionFactory->expects($this->once())->method('create')->willReturn($collection);
95-
$collection->expects($this->once())->method('addFieldToFilter')
96-
->with(ProductInterface::SKU, ['in' => $skus])->willReturnSelf();
97-
$collection->expects($this->atLeastOnce())->method('getItems')->willReturn([$product]);
98-
$collection->expects($this->atLeastOnce())->method('setPageSize')->willReturnSelf();
99-
$collection->expects($this->atLeastOnce())->method('getLastPageNumber')->willReturn(1);
100-
$collection->expects($this->atLeastOnce())->method('setCurPage')->with(1)->willReturnSelf();
101-
$collection->expects($this->atLeastOnce())->method('clear')->willReturnSelf();
102-
$this->metadataPool
103-
->expects($this->once())
104-
->method('getMetadata')
105-
->with(ProductInterface::class)
106-
->willReturn($metaDataInterface);
107-
$metaDataInterface->expects($this->once())->method('getLinkField')->willReturn('entity_id');
108-
$product->expects($this->once())->method('getSku')->willReturn('sku_1');
109-
$product->expects($this->once())->method('getData')->with('entity_id')->willReturn(1);
110-
$product->expects($this->once())->method('getTypeId')->willReturn('simple');
79+
$product->method('getSku')
80+
->willReturn('sku_1');
81+
$product->method('getData')
82+
->with($this->linkField)
83+
->willReturn(1);
84+
$product->method('getTypeId')
85+
->willReturn('simple');
86+
87+
$this->collection->expects($this->once())
88+
->method('addFieldToFilter')
89+
->with(ProductInterface::SKU, ['in' => $skus])
90+
->willReturnSelf();
91+
$this->collection->expects($this->atLeastOnce())
92+
->method('getItems')
93+
->willReturn([$product]);
94+
$this->collection->expects($this->atLeastOnce())
95+
->method('setPageSize')
96+
->willReturnSelf();
97+
$this->collection->expects($this->atLeastOnce())
98+
->method('getLastPageNumber')
99+
->willReturn(1);
100+
$this->collection->expects($this->atLeastOnce())
101+
->method('setCurPage')
102+
->with(1)
103+
->willReturnSelf();
104+
$this->collection->expects($this->atLeastOnce())
105+
->method('clear')
106+
->willReturnSelf();
107+
111108
$this->assertEquals(
112109
['sku_1' => [1 => 'simple']],
113110
$this->model->retrieveProductIdsBySkus($skus)
114111
);
115112
}
113+
114+
public function testRetrieveProductIdsWithNumericSkus()
115+
{
116+
$skus = ['111', '222', '333', '444', '555'];
117+
$products = [];
118+
foreach ($skus as $sku) {
119+
$product = $this->getMockBuilder(ProductInterface::class)
120+
->setMethods(['getSku', 'getData', 'getTypeId'])
121+
->disableOriginalConstructor()
122+
->getMockForAbstractClass();
123+
$product->method('getSku')
124+
->willReturn($sku);
125+
$product->method('getData')
126+
->with($this->linkField)
127+
->willReturn((int) $sku);
128+
$product->method('getTypeId')
129+
->willReturn('simple');
130+
$products[] = $product;
131+
}
132+
133+
$this->collection->expects($this->atLeastOnce())
134+
->method('addFieldToFilter')
135+
->withConsecutive([ProductInterface::SKU, ['in' => $skus]], [ProductInterface::SKU, ['in' => ['1']]])
136+
->willReturnSelf();
137+
$this->collection->expects($this->atLeastOnce())
138+
->method('getItems')
139+
->willReturnOnConsecutiveCalls($products, []);
140+
$this->collection->expects($this->atLeastOnce())
141+
->method('setPageSize')
142+
->willReturnSelf();
143+
$this->collection->expects($this->atLeastOnce())
144+
->method('getLastPageNumber')
145+
->willReturn(1);
146+
$this->collection->expects($this->atLeastOnce())
147+
->method('setCurPage')
148+
->with(1)
149+
->willReturnSelf();
150+
$this->collection->expects($this->atLeastOnce())
151+
->method('clear')
152+
->willReturnSelf();
153+
154+
$this->assertEquals(
155+
[
156+
'111' => [111 => 'simple'],
157+
'222' => [222 => 'simple'],
158+
'333' => [333 => 'simple'],
159+
'444' => [444 => 'simple'],
160+
'555' => [555 => 'simple'],
161+
],
162+
$this->model->retrieveProductIdsBySkus($skus)
163+
);
164+
$this->assertEmpty($this->model->retrieveProductIdsBySkus(['1']));
165+
}
116166
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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\CatalogImportExport\Model\Export\Product;
9+
10+
use Magento\Catalog\Model\ResourceModel\Product\Collection;
11+
use Magento\CatalogImportExport\Model\Export\ProductFilterInterface;
12+
13+
/**
14+
* Website filter for products export
15+
*/
16+
class WebsiteFilter implements ProductFilterInterface
17+
{
18+
private const NAME = 'website_id';
19+
20+
/**
21+
* @inheritDoc
22+
*/
23+
public function filter(Collection $collection, array $filters): Collection
24+
{
25+
if (!isset($filters[self::NAME])) {
26+
return $collection;
27+
}
28+
29+
$collection->addWebsiteFilter($filters[self::NAME]);
30+
31+
return $collection;
32+
}
33+
}

app/code/Magento/CatalogImportExport/etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
<argument name="filters" xsi:type="array">
4949
<item name="category_ids" xsi:type="object">Magento\CatalogImportExport\Model\Export\Product\CategoryFilter</item>
5050
<item name="quantity_and_stock_status" xsi:type="object">Magento\CatalogImportExport\Model\Export\Product\StockStatusFilter</item>
51+
<item name="website_ids" xsi:type="object">Magento\CatalogImportExport\Model\Export\Product\WebsiteFilter</item>
5152
</argument>
5253
</arguments>
5354
</type>

0 commit comments

Comments
 (0)