Skip to content

Commit 8f5e6e1

Browse files
authored
Merge pull request #1398 from magento-okapis/Okapis-PR
[okapis] Bugs
2 parents ef5da4d + c7fbd54 commit 8f5e6e1

File tree

29 files changed

+926
-105
lines changed

29 files changed

+926
-105
lines changed

app/code/Magento/Catalog/Model/Product/Attribute/Backend/Price.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ public function afterSave($object)
128128
$attribute = $this->getAttribute();
129129
$attributeCode = $attribute->getAttributeCode();
130130
$value = $object->getData($attributeCode);
131-
if ((float)$value > 0) {
131+
// $value may be passed as null to unset the attribute
132+
if ($value === null || (float)$value > 0) {
132133
if ($attribute->isScopeWebsite() && $object->getStoreId() != \Magento\Store\Model\Store::DEFAULT_STORE_ID) {
133134
if ($this->isUseDefault($object)) {
134135
$value = null;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Observer;
7+
8+
use Magento\Framework\Event\ObserverInterface;
9+
10+
/**
11+
* Unset value for Special Price if passed as null
12+
*/
13+
class UnsetSpecialPrice implements ObserverInterface
14+
{
15+
/**
16+
* Unset the Special Price attribute if it is null
17+
*
18+
* @param \Magento\Framework\Event\Observer $observer
19+
* @return $this
20+
*/
21+
public function execute(\Magento\Framework\Event\Observer $observer)
22+
{
23+
/** @var $product \Magento\Catalog\Model\Product */
24+
$product = $observer->getEvent()->getProduct();
25+
if ($product->getSpecialPrice() === null) {
26+
$product->setData('special_price', '');
27+
}
28+
29+
return $this;
30+
}
31+
}

app/code/Magento/Catalog/etc/events.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
</event>
5757
<event name="catalog_product_save_before">
5858
<observer name="set_special_price_start_date" instance="Magento\Catalog\Observer\SetSpecialPriceStartDate" />
59+
<observer name="unset_special_price" instance="Magento\Catalog\Observer\UnsetSpecialPrice" />
5960
</event>
6061
<event name="store_save_after">
6162
<observer name="synchronize_website_attributes" instance="Magento\Catalog\Observer\SynchronizeWebsiteAttributesOnStoreChange" />

app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php

Lines changed: 103 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
use Magento\Framework\App\ResourceConnection;
1313
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
1414
use Magento\Catalog\Api\Data\ProductInterface;
15+
use Magento\Catalog\Model\ResourceModel\Product\Option\Value\Collection as ProductOptionValueCollection;
16+
use Magento\Catalog\Model\ResourceModel\Product\Option\Value\CollectionFactory as ProductOptionValueCollectionFactory;
1517

1618
/**
1719
* Entity class which provide possibility to import product custom options
@@ -320,6 +322,16 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
320322
*/
321323
private $productEntityIdentifierField;
322324

325+
/**
326+
* @var ProductOptionValueCollectionFactory
327+
*/
328+
private $productOptionValueCollectionFactory;
329+
330+
/**
331+
* @var array
332+
*/
333+
private $optionTypeTitles;
334+
323335
/**
324336
* @param \Magento\ImportExport\Model\ResourceModel\Import\Data $importData
325337
* @param ResourceConnection $resource
@@ -333,6 +345,7 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
333345
* @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $dateTime
334346
* @param ProcessingErrorAggregatorInterface $errorAggregator
335347
* @param array $data
348+
* @param ProductOptionValueCollectionFactory $productOptionValueCollectionFactory
336349
* @throws \Magento\Framework\Exception\LocalizedException
337350
*
338351
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
@@ -349,7 +362,8 @@ public function __construct(
349362
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
350363
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $dateTime,
351364
ProcessingErrorAggregatorInterface $errorAggregator,
352-
array $data = []
365+
array $data = [],
366+
ProductOptionValueCollectionFactory $productOptionValueCollectionFactory = null
353367
) {
354368
$this->_resource = $resource;
355369
$this->_catalogData = $catalogData;
@@ -360,6 +374,8 @@ public function __construct(
360374
$this->_colIteratorFactory = $colIteratorFactory;
361375
$this->_scopeConfig = $scopeConfig;
362376
$this->dateTime = $dateTime;
377+
$this->productOptionValueCollectionFactory = $productOptionValueCollectionFactory
378+
?: \Magento\Framework\App\ObjectManager::getInstance()->get(ProductOptionValueCollectionFactory::class);
363379

364380
if (isset($data['connection'])) {
365381
$this->_connection = $data['connection'];
@@ -1121,7 +1137,7 @@ private function processOptionRow($name, $optionRow)
11211137
if (isset($optionRow['price'])) {
11221138
$percent_suffix = '';
11231139
if (isset($optionRow['price_type']) && $optionRow['price_type'] == 'percent') {
1124-
$percent_suffix = '%';
1140+
$percent_suffix = '%';
11251141
}
11261142
$result[self::COLUMN_ROW_PRICE] = $optionRow['price'] . $percent_suffix;
11271143
}
@@ -1230,6 +1246,7 @@ protected function _importData()
12301246
if ($this->_isReadyForSaving($options, $titles, $typeValues)) {
12311247
if ($this->getBehavior() == \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND) {
12321248
$this->_compareOptionsWithExisting($options, $titles, $prices, $typeValues);
1249+
$this->restoreOriginalOptionTypeIds($typeValues, $typePrices, $typeTitles);
12331250
}
12341251

12351252
$this->_saveOptions(
@@ -1296,12 +1313,12 @@ protected function _collectOptionMainData(
12961313
$optionData = $this->_getOptionData($rowData, $this->_rowProductId, $nextOptionId, $this->_rowType);
12971314

12981315
if (!$this->_isRowHasSpecificType(
1299-
$this->_rowType
1300-
) && ($priceData = $this->_getPriceData(
1301-
$rowData,
1302-
$nextOptionId,
1303-
$this->_rowType
1304-
))
1316+
$this->_rowType
1317+
) && ($priceData = $this->_getPriceData(
1318+
$rowData,
1319+
$nextOptionId,
1320+
$this->_rowType
1321+
))
13051322
) {
13061323
$prices[$nextOptionId] = $priceData;
13071324
}
@@ -1434,6 +1451,68 @@ protected function _compareOptionsWithExisting(array &$options, array &$titles,
14341451
return $this;
14351452
}
14361453

1454+
/**
1455+
* Restore original IDs for existing option types.
1456+
*
1457+
* Warning: arguments are modified by reference
1458+
*
1459+
* @param array $typeValues
1460+
* @param array $typePrices
1461+
* @param array $typeTitles
1462+
* @return void
1463+
*/
1464+
private function restoreOriginalOptionTypeIds(array &$typeValues, array &$typePrices, array &$typeTitles)
1465+
{
1466+
foreach ($typeValues as $optionId => &$optionTypes) {
1467+
foreach ($optionTypes as &$optionType) {
1468+
$optionTypeId = $optionType['option_type_id'];
1469+
foreach ($typeTitles[$optionTypeId] as $storeId => $optionTypeTitle) {
1470+
$existingTypeId = $this->getExistingOptionTypeId($optionId, $storeId, $optionTypeTitle);
1471+
if ($existingTypeId) {
1472+
$optionType['option_type_id'] = $existingTypeId;
1473+
$typeTitles[$existingTypeId] = $typeTitles[$optionTypeId];
1474+
unset($typeTitles[$optionTypeId]);
1475+
$typePrices[$existingTypeId] = $typePrices[$optionTypeId];
1476+
unset($typePrices[$optionTypeId]);
1477+
// If option type titles match at least in one store, consider current option type as existing
1478+
break;
1479+
}
1480+
}
1481+
}
1482+
}
1483+
}
1484+
1485+
/**
1486+
* Identify ID of the provided option type by its title in the specified store.
1487+
*
1488+
* @param int $optionId
1489+
* @param int $storeId
1490+
* @param string $optionTypeTitle
1491+
* @return int|null
1492+
*/
1493+
private function getExistingOptionTypeId($optionId, $storeId, $optionTypeTitle)
1494+
{
1495+
if (!isset($this->optionTypeTitles[$storeId])) {
1496+
/** @var ProductOptionValueCollection $optionTypeCollection */
1497+
$optionTypeCollection = $this->productOptionValueCollectionFactory->create();
1498+
$optionTypeCollection->addTitleToResult($storeId);
1499+
/** @var \Magento\Catalog\Model\Product\Option\Value $type */
1500+
foreach ($optionTypeCollection as $type) {
1501+
$this->optionTypeTitles[$storeId][$type->getOptionId()][$type->getId()] = $type->getTitle();
1502+
}
1503+
}
1504+
if (isset($this->optionTypeTitles[$storeId][$optionId])
1505+
&& is_array($this->optionTypeTitles[$storeId][$optionId])
1506+
) {
1507+
foreach ($this->optionTypeTitles[$storeId][$optionId] as $optionTypeId => $currentTypeTitle) {
1508+
if ($optionTypeTitle === $currentTypeTitle) {
1509+
return $optionTypeId;
1510+
}
1511+
}
1512+
}
1513+
return null;
1514+
}
1515+
14371516
/**
14381517
* Parse required data from current row and store to class internal variables some data
14391518
* for underlying dependent rows
@@ -1565,13 +1644,13 @@ protected function _getOptionData(array $rowData, $productId, $optionId, $type)
15651644
protected function _getPriceData(array $rowData, $optionId, $type)
15661645
{
15671646
if (in_array(
1568-
'price',
1569-
$this->_specificTypes[$type]
1570-
) && isset(
1571-
$rowData[self::COLUMN_PREFIX . 'price']
1572-
) && strlen(
1573-
$rowData[self::COLUMN_PREFIX . 'price']
1574-
) > 0
1647+
'price',
1648+
$this->_specificTypes[$type]
1649+
) && isset(
1650+
$rowData[self::COLUMN_PREFIX . 'price']
1651+
) && strlen(
1652+
$rowData[self::COLUMN_PREFIX . 'price']
1653+
) > 0
15751654
) {
15761655
$priceData = [
15771656
'option_id' => $optionId,
@@ -1821,13 +1900,17 @@ protected function _updateProducts(array $data)
18211900
* @return array
18221901
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
18231902
*/
1824-
protected function _parseCustomOptions($rowData)
1903+
protected function _parseCustomOptions($rowData)
18251904
{
18261905
$beforeOptionValueSkuDelimiter = ';';
18271906
if (empty($rowData['custom_options'])) {
18281907
return $rowData;
18291908
}
1830-
$rowData['custom_options'] = str_replace($beforeOptionValueSkuDelimiter, $this->_productEntity->getMultipleValueSeparator(), $rowData['custom_options']);
1909+
$rowData['custom_options'] = str_replace(
1910+
$beforeOptionValueSkuDelimiter,
1911+
$this->_productEntity->getMultipleValueSeparator(),
1912+
$rowData['custom_options']
1913+
);
18311914
$options = [];
18321915
$optionValues = explode(Product::PSEUDO_MULTI_LINE_SEPARATOR, $rowData['custom_options']);
18331916
$k = 0;
@@ -1839,7 +1922,7 @@ protected function _parseCustomOptions($rowData)
18391922
if (!empty($nameAndValue)) {
18401923
$value = isset($nameAndValue[1]) ? $nameAndValue[1] : '';
18411924
$value = trim($value);
1842-
$fieldName = trim($nameAndValue[0]);
1925+
$fieldName = trim($nameAndValue[0]);
18431926
if ($value && ($fieldName == 'name')) {
18441927
if ($name != $value) {
18451928
$name = $value;
@@ -1878,7 +1961,7 @@ private function getProductEntityLinkField()
18781961
{
18791962
if (!$this->productEntityLinkField) {
18801963
$this->productEntityLinkField = $this->getMetadataPool()
1881-
->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
1964+
->getMetadata(ProductInterface::class)
18821965
->getLinkField();
18831966
}
18841967
return $this->productEntityLinkField;
@@ -1893,7 +1976,7 @@ private function getProductIdentifierField()
18931976
{
18941977
if (!$this->productEntityIdentifierField) {
18951978
$this->productEntityIdentifierField = $this->getMetadataPool()
1896-
->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
1979+
->getMetadata(ProductInterface::class)
18971980
->getIdentifierField();
18981981
}
18991982
return $this->productEntityIdentifierField;

app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractIm
215215

216216
/**
217217
* Init entity adapter model
218+
*
219+
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
218220
*/
219221
protected function setUp()
220222
{
@@ -249,6 +251,17 @@ protected function setUp()
249251
$entityMetadataMock->expects($this->any())
250252
->method('getLinkField')
251253
->willReturn('entity_id');
254+
$optionValueCollectionFactoryMock = $this->createMock(
255+
\Magento\Catalog\Model\ResourceModel\Product\Option\Value\CollectionFactory::class
256+
);
257+
$optionValueCollectionMock = $this->createPartialMock(
258+
\Magento\Catalog\Model\ResourceModel\Product\Option\Value\Collection::class,
259+
['getIterator', 'addTitleToResult']
260+
);
261+
$optionValueCollectionMock->expects($this->any())->method('getIterator')
262+
->willReturn($this->createMock(\Traversable::class));
263+
$optionValueCollectionFactoryMock->expects($this->any())
264+
->method('create')->willReturn($optionValueCollectionMock);
252265
$modelClassArgs = [
253266
$this->createMock(\Magento\ImportExport\Model\ResourceModel\Import\Data::class),
254267
$this->createMock(\Magento\Framework\App\ResourceConnection::class),
@@ -263,7 +276,8 @@ protected function setUp()
263276
$this->createMock(
264277
\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface::class
265278
),
266-
$this->_getModelDependencies($addExpectations, $deleteBehavior, $doubleOptions)
279+
$this->_getModelDependencies($addExpectations, $deleteBehavior, $doubleOptions),
280+
$optionValueCollectionFactoryMock
267281
];
268282

269283
$modelClassName = \Magento\CatalogImportExport\Model\Import\Product\Option::class;

app/code/Magento/Deploy/Model/Filesystem.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ public function regenerateStatic(
147147
DirectoryList::CACHE,
148148
DirectoryList::GENERATED_CODE,
149149
DirectoryList::GENERATED_METADATA,
150-
DirectoryList::TMP_MATERIALIZATION_DIR
150+
DirectoryList::TMP_MATERIALIZATION_DIR,
151+
DirectoryList::STATIC_VIEW
151152
]
152153
);
153154

0 commit comments

Comments
 (0)