Skip to content

Commit e53e613

Browse files
Merge pull request #8685 from magento-l3/Tier4-Kings-PR-12-18-2023
Tier4 Kings PR Delivery 12.18.2023
2 parents 59b2921 + ee2cf8c commit e53e613

File tree

5 files changed

+116
-25
lines changed

5 files changed

+116
-25
lines changed

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

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
class Product extends AbstractEntity
5454
{
5555
private const COL_NAME_FORMAT = '/[\x00-\x1F\x7F]/';
56-
private const DEFAULT_GLOBAL_MULTIPLE_VALUE_SEPARATOR = ',';
5756
public const CONFIG_KEY_PRODUCT_TYPES = 'global/importexport/import_product_types';
5857

5958
/**
@@ -939,7 +938,7 @@ public function __construct(
939938
$this->_optionEntity = $data['option_entity'] ??
940939
$optionFactory->create(['data' => ['product_entity' => $this]]);
941940
$this->skuStorage = $skuStorage ?? ObjectManager::getInstance()
942-
->get(SkuStorage::class);
941+
->get(SkuStorage::class);
943942
$this->_initAttributeSets()
944943
->_initTypeModels()
945944
->_initSkus()
@@ -949,7 +948,7 @@ public function __construct(
949948
$this->productRepository = $productRepository ?? ObjectManager::getInstance()
950949
->get(ProductRepositoryInterface::class);
951950
$this->stockItemProcessor = $stockItemProcessor ?? ObjectManager::getInstance()
952-
->get(StockItemProcessorInterface::class);
951+
->get(StockItemProcessorInterface::class);
953952
}
954953

955954
/**
@@ -2837,7 +2836,7 @@ private function prepareNewSkuData($sku)
28372836
*
28382837
* @return array
28392838
*/
2840-
private function _parseAdditionalAttributes($rowData)
2839+
private function _parseAdditionalAttributes(array $rowData): array
28412840
{
28422841
if (empty($rowData['additional_attributes'])) {
28432842
return $rowData;
@@ -2847,7 +2846,7 @@ private function _parseAdditionalAttributes($rowData)
28472846
$rowData[mb_strtolower($key)] = $value;
28482847
}
28492848
} else {
2850-
$rowData = array_merge($rowData, $this->getAdditionalAttributes($rowData['additional_attributes']));
2849+
$rowData = array_merge($rowData, $this->getAdditionalAttributes($rowData));
28512850
}
28522851
return $rowData;
28532852
}
@@ -2861,14 +2860,14 @@ private function _parseAdditionalAttributes($rowData)
28612860
* codeN => valueN
28622861
* ]
28632862
*
2864-
* @param string $additionalAttributes Attributes data that will be parsed
2863+
* @param array $rowData
28652864
* @return array
28662865
*/
2867-
private function getAdditionalAttributes($additionalAttributes)
2866+
private function getAdditionalAttributes(array $rowData): array
28682867
{
28692868
return empty($this->_parameters[Import::FIELDS_ENCLOSURE])
2870-
? $this->parseAttributesWithoutWrappedValues($additionalAttributes)
2871-
: $this->parseAttributesWithWrappedValues($additionalAttributes);
2869+
? $this->parseAttributesWithoutWrappedValues($rowData['additional_attributes'], $rowData['product_type'])
2870+
: $this->parseAttributesWithWrappedValues($rowData['additional_attributes']);
28722871
}
28732872

28742873
/**
@@ -2882,9 +2881,10 @@ private function getAdditionalAttributes($additionalAttributes)
28822881
*
28832882
* @param string $attributesData Attributes data that will be parsed. It keeps data in format:
28842883
* code=value,code2=value2...,codeN=valueN
2884+
* @param string $productType
28852885
* @return array
28862886
*/
2887-
private function parseAttributesWithoutWrappedValues($attributesData)
2887+
private function parseAttributesWithoutWrappedValues(string $attributesData, string $productType): array
28882888
{
28892889
$attributeNameValuePairs = explode($this->getMultipleValueSeparator(), $attributesData);
28902890
$preparedAttributes = [];
@@ -2900,6 +2900,17 @@ private function parseAttributesWithoutWrappedValues($attributesData)
29002900
}
29012901
list($code, $value) = explode(self::PAIR_NAME_VALUE_SEPARATOR, $attributeData, 2);
29022902
$code = mb_strtolower($code);
2903+
2904+
$entityTypeModel = $this->retrieveProductTypeByName($productType);
2905+
if ($entityTypeModel) {
2906+
$attrParams = $entityTypeModel->retrieveAttributeFromCache($code);
2907+
if (!empty($attrParams) && $attrParams['type'] == 'multiselect') {
2908+
$parsedValue = $this->parseMultiselectValues($value, self::PSEUDO_MULTI_LINE_SEPARATOR);
2909+
if (count($parsedValue) > 1) {
2910+
$value = $parsedValue;
2911+
}
2912+
}
2913+
}
29032914
$preparedAttributes[$code] = $value;
29042915
}
29052916
return $preparedAttributes;
@@ -2949,10 +2960,13 @@ private function parseAttributesWithWrappedValues($attributesData)
29492960
* @return array
29502961
* @since 100.1.2
29512962
*/
2952-
public function parseMultiselectValues($values, $delimiter = self::PSEUDO_MULTI_LINE_SEPARATOR)
2963+
public function parseMultiselectValues($values, $delimiter = '')
29532964
{
29542965
if (empty($this->_parameters[Import::FIELDS_ENCLOSURE])) {
2955-
if ($this->getMultipleValueSeparator() !== self::DEFAULT_GLOBAL_MULTIPLE_VALUE_SEPARATOR) {
2966+
if (is_array($values)) {
2967+
return $values;
2968+
}
2969+
if (!$delimiter) {
29562970
$delimiter = $this->getMultipleValueSeparator();
29572971
}
29582972

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protected function setUp(): void
4747
$entityTypeModel->expects($this->any())->method('retrieveAttributeFromCache')->willReturn([]);
4848
$this->context = $this->createPartialMock(
4949
Product::class,
50-
['retrieveProductTypeByName', 'retrieveMessageTemplate', 'getBehavior']
50+
['retrieveProductTypeByName', 'retrieveMessageTemplate', 'getBehavior', 'getMultipleValueSeparator']
5151
);
5252
$this->context->expects($this->any())->method('retrieveProductTypeByName')->willReturn($entityTypeModel);
5353
$this->context->expects($this->any())->method('retrieveMessageTemplate')->willReturn('error message');
@@ -83,6 +83,7 @@ protected function setUp(): void
8383
*/
8484
public function testAttributeValidation($behavior, $attrParams, $rowData, $isValid, $attrCode = 'attribute_code')
8585
{
86+
$this->context->method('getMultipleValueSeparator')->willReturn(Product::PSEUDO_MULTI_LINE_SEPARATOR);
8687
$this->context->expects($this->any())->method('getBehavior')->willReturn($behavior);
8788
$result = $this->validator->isAttributeValid(
8889
$attrCode,

app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Magento\CatalogInventory\Api\StockConfigurationInterface;
2626
use Magento\CatalogInventory\Api\StockRegistryInterface;
2727
use Magento\CatalogInventory\Model\Spi\StockStateProviderInterface;
28+
use Magento\ConfigurableImportExport\Model\Import\Product\Type\Configurable;
2829
use Magento\Eav\Model\Config;
2930
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
3031
use Magento\Eav\Model\Entity\Attribute\Set;
@@ -1471,18 +1472,32 @@ public function testGetImagesFromRow($rowData, $expectedResult): void
14711472
*/
14721473
public function testParseAttributesWithoutWrappedValuesWillReturnsLowercasedAttributeCodes(): void
14731474
{
1474-
$attributesData = 'PARAM1=value1,param2=value2';
1475+
$entityTypeModel = $this->createPartialMock(
1476+
Configurable::class,
1477+
['retrieveAttributeFromCache']
1478+
);
1479+
$entityTypeModel->expects($this->exactly(2))->method('retrieveAttributeFromCache')->willReturn([
1480+
'type' => 'multiselect'
1481+
]);
1482+
$importProduct = $this->getMockBuilder(Product::class)
1483+
->disableOriginalConstructor()
1484+
->onlyMethods(['retrieveProductTypeByName'])
1485+
->getMock();
1486+
$importProduct->expects($this->exactly(2))->method('retrieveProductTypeByName')->willReturn($entityTypeModel);
1487+
1488+
$attributesData = 'PARAM1=value1,param2=value2|value3';
14751489
$preparedAttributes = $this->invokeMethod(
1476-
$this->importProduct,
1490+
$importProduct,
14771491
'parseAttributesWithoutWrappedValues',
1478-
[$attributesData]
1492+
[$attributesData, 'configurable']
14791493
);
14801494

14811495
$this->assertArrayHasKey('param1', $preparedAttributes);
14821496
$this->assertEquals('value1', $preparedAttributes['param1']);
14831497

14841498
$this->assertArrayHasKey('param2', $preparedAttributes);
1485-
$this->assertEquals('value2', $preparedAttributes['param2']);
1499+
$this->assertEquals('value2', $preparedAttributes['param2'][0]);
1500+
$this->assertEquals('value3', $preparedAttributes['param2'][1]);
14861501

14871502
$this->assertArrayNotHasKey('PARAM1', $preparedAttributes);
14881503
}
@@ -1684,7 +1699,7 @@ public function productCategoriesDataProvider()
16841699
],
16851700
'catalog_category_product',
16861701
[
1687-
[2, 5],
1702+
[2, 5],
16881703
[
16891704
[
16901705
'product_id' => 2,
@@ -2191,4 +2206,57 @@ protected function createModelMockWithErrorAggregator(
21912206

21922207
return $importProduct;
21932208
}
2209+
2210+
/**
2211+
* @dataProvider valuesDataProvider
2212+
*/
2213+
public function testParseMultiselectValues($value, $fieldSeparator, $valueSeparator)
2214+
{
2215+
$this->importProduct->setParameters(
2216+
[
2217+
Import::FIELD_FIELD_SEPARATOR => $fieldSeparator,
2218+
Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR => $valueSeparator
2219+
]
2220+
);
2221+
$this->assertEquals(explode($valueSeparator, $value), $this->importProduct->parseMultiselectValues($value));
2222+
}
2223+
2224+
/**
2225+
* @return array
2226+
*/
2227+
public function valuesDataProvider(): array
2228+
{
2229+
return [
2230+
'pipeWithCustomFieldSeparator' => [
2231+
'value' => 'L|C|D|T|H',
2232+
'fieldSeparator' => ';',
2233+
'valueSeparator' => '|'
2234+
],
2235+
'commaWithCustomFieldSeparator' => [
2236+
'value' => 'L,C,D,T,H',
2237+
'fieldSeparator' => ';',
2238+
'valueSeparator' => ','
2239+
],
2240+
'pipeWithDefaultFieldSeparator' => [
2241+
'value' => 'L|C|D|T|H',
2242+
'fieldSeparator' => ',',
2243+
'valueSeparator' => '|'
2244+
],
2245+
'commaWithDefaultFieldSeparator' => [
2246+
'value' => 'L,C,D,T,H',
2247+
'fieldSeparator' => ',',
2248+
'valueSeparator' => ','
2249+
],
2250+
'anonymousValueSeparatorWithDefaultFieldSeparator' => [
2251+
'value' => 'L+C+D+T+H',
2252+
'fieldSeparator' => ',',
2253+
'valueSeparator' => '+'
2254+
],
2255+
'anonymousValueSeparatorWithDefaultFieldSeparatorAndSingleValue' => [
2256+
'value' => 'L',
2257+
'fieldSeparator' => ',',
2258+
'valueSeparator' => '*'
2259+
]
2260+
];
2261+
}
21942262
}

app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public function collectRates(RateRequest $request)
132132
if ($item->getHasChildren() && $item->isShipSeparately()) {
133133
foreach ($item->getChildren() as $child) {
134134
if ($child->getFreeShipping() && !$child->getProduct()->isVirtual()) {
135-
$freeShipping = is_numeric($child->getFreeShipping()) ? $child->getFreeShipping() : 0;
135+
$freeShipping = (int)$child->getFreeShipping();
136136
$freeQty += $item->getQty() * ($child->getQty() - $freeShipping);
137137
}
138138
}

app/code/Magento/OfflineShipping/Test/Unit/Model/Carrier/TablerateTest.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,11 @@ protected function setUp(): void
118118

119119
/**
120120
* @param bool $freeshipping
121+
* @param bool $isShipSeparately
121122
* @dataProvider collectRatesWithGlobalFreeShippingDataProvider
122123
* @return void
123124
*/
124-
public function testCollectRatesWithGlobalFreeShipping($freeshipping)
125+
public function testCollectRatesWithGlobalFreeShipping($freeshipping, $isShipSeparately)
125126
{
126127
$rate = [
127128
'price' => 15,
@@ -177,11 +178,17 @@ public function testCollectRatesWithGlobalFreeShipping($freeshipping)
177178
$this->resultFactoryMock->expects($this->once())->method('create')->willReturn($result);
178179

179180
$product->expects($this->any())->method('isVirtual')->willReturn(false);
180-
181181
$item->expects($this->any())->method('getProduct')->willReturn($product);
182-
$item->expects($this->any())->method('getFreeShipping')->willReturn(1);
183182
$item->expects($this->any())->method('getQty')->willReturn(1);
184-
183+
if ($isShipSeparately) {
184+
$freeShippingReturnValue = true;
185+
$item->expects($this->any())->method('getHasChildren')->willReturn(1);
186+
$item->expects($this->any())->method('isShipSeparately')->willReturn(1);
187+
$item->expects($this->any())->method('getChildren')->willReturn([$item]);
188+
} else {
189+
$freeShippingReturnValue = "1";
190+
}
191+
$item->expects($this->any())->method('getFreeShipping')->willReturn($freeShippingReturnValue);
185192
$request->expects($this->any())->method('getAllItems')->willReturn([$item]);
186193
$request->expects($this->any())->method('getPackageQty')->willReturn(1);
187194

@@ -225,8 +232,9 @@ private function captureArg(&$captureVar)
225232
public function collectRatesWithGlobalFreeShippingDataProvider()
226233
{
227234
return [
228-
['freeshipping' => true],
229-
['freeshipping' => false]
235+
['freeshipping' => true, 'isShipSeparately' => false],
236+
['freeshipping' => false, 'isShipSeparately' => false],
237+
['freeshipping' => true, 'isShipSeparately' => true]
230238
];
231239
}
232240
}

0 commit comments

Comments
 (0)