Skip to content

Commit 33d6720

Browse files
author
mtanniru
committed
Merge remote-tracking branch 'remotes/mainline/develop' into MAGETWO-58348-Cannot-create-configurable-product-with-child-by-REST-API-2.2
2 parents fb370d1 + 5950439 commit 33d6720

File tree

6 files changed

+225
-126
lines changed

6 files changed

+225
-126
lines changed

app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -315,17 +315,6 @@ protected function customizeNameListeners(array $meta)
315315
$importsConfig = [
316316
'mask' => $this->locator->getStore()->getConfig('catalog/fields_masks/' . $listener),
317317
'component' => 'Magento_Catalog/js/components/import-handler',
318-
'imports' => [
319-
'handleNameChanges' => '${$.provider}:data.product.name',
320-
'handleDescriptionChanges' => '${$.provider}:data.product.description',
321-
'handleSkuChanges' => '${$.provider}:data.product.sku',
322-
'handleColorChanges' => '${$.provider}:data.product.color',
323-
'handleCountryChanges' => '${$.provider}:data.product.country_of_manufacture',
324-
'handleGenderChanges' => '${$.provider}:data.product.gender',
325-
'handleMaterialChanges' => '${$.provider}:data.product.material',
326-
'handleShortDescriptionChanges' => '${$.provider}:data.product.short_description',
327-
'handleSizeChanges' => '${$.provider}:data.product.size'
328-
],
329318
'allowImport' => !$this->locator->getProduct()->getId(),
330319
];
331320

app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js

Lines changed: 51 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -4,148 +4,78 @@
44
*/
55

66
define([
7+
'Magento_Ui/js/form/element/abstract',
78
'underscore',
8-
'Magento_Ui/js/form/element/textarea'
9-
], function (_, Textarea) {
9+
'uiRegistry'
10+
], function (Abstract, _, registry) {
1011
'use strict';
1112

12-
return Textarea.extend({
13+
return Abstract.extend({
1314
defaults: {
1415
allowImport: true,
1516
autoImportIfEmpty: false,
16-
values: {
17-
'name': '',
18-
'description': '',
19-
'sku': '',
20-
'color': '',
21-
'country_of_manufacture': '',
22-
'gender': '',
23-
'material': '',
24-
'short_description': '',
25-
'size': ''
26-
},
27-
valueUpdate: 'input',
28-
mask: ''
17+
values: {},
18+
mask: '',
19+
queryTemplate: 'ns = ${ $.ns }, index = '
2920
},
3021

31-
/**
32-
* Handle name value changes, if it's allowed
33-
*
34-
* @param {String} newValue
35-
*/
36-
handleNameChanges: function (newValue) {
37-
this.values.name = newValue;
38-
this.updateValue();
39-
},
40-
41-
/**
42-
* Handle description value changes, if it's allowed
43-
*
44-
* @param {String} newValue
45-
*/
46-
handleDescriptionChanges: function (newValue) {
47-
this.values.description = newValue;
48-
this.updateValue();
49-
},
22+
/** @inheritdoc */
23+
initialize: function () {
24+
this._super();
5025

51-
/**
52-
* Handle sku value changes, if it's allowed
53-
*
54-
* @param {String} newValue
55-
*/
56-
handleSkuChanges: function (newValue) {
57-
if (this.code !== 'sku') {
58-
this.values.sku = newValue;
59-
this.updateValue();
26+
if (this.allowImport) {
27+
this.setHandlers();
6028
}
6129
},
6230

6331
/**
64-
* Handle color value changes, if it's allowed
65-
*
66-
* @param {String} newValue
67-
*/
68-
handleColorChanges: function (newValue) {
69-
this.values.color = newValue;
70-
this.updateValue();
71-
},
72-
73-
/**
74-
* Handle country value changes, if it's allowed
75-
*
76-
* @param {String} newValue
32+
* Split mask placeholder and attach events to placeholder fields.
7733
*/
78-
handleCountryChanges: function (newValue) {
79-
this.values.country = newValue;
80-
this.updateValue();
81-
},
34+
setHandlers: function () {
35+
var str = this.mask || '',
36+
placeholders;
8237

83-
/**
84-
* Handle gender value changes, if it's allowed
85-
*
86-
* @param {String} newValue
87-
*/
88-
handleGenderChanges: function (newValue) {
89-
this.values.gender = newValue;
90-
this.updateValue();
91-
},
38+
placeholders = str.match(/{{(.*?)}}/g); // Get placeholders
9239

93-
/**
94-
* Handle material value changes, if it's allowed
95-
*
96-
* @param {String} newValue
97-
*/
98-
handleMaterialChanges: function (newValue) {
99-
this.values.material = newValue;
100-
this.updateValue();
101-
},
40+
_.each(placeholders, function (placeholder) {
41+
placeholder = placeholder.replace(/[{{}}]/g, ''); // Remove curly braces
10242

103-
/**
104-
* Handle short description value changes, if it's allowed
105-
*
106-
* @param {String} newValue
107-
*/
108-
handleShortDescriptionChanges: function (newValue) {
109-
this.values['short_description'] = newValue;
110-
this.updateValue();
43+
registry.get(this.queryTemplate + placeholder, function (component) {
44+
this.values[placeholder] = component.getPreview();
45+
component.on('value', this.updateValue.bind(this, placeholder, component));
46+
component.valueUpdate = 'keyup';
47+
}.bind(this));
48+
}, this);
11149
},
11250

11351
/**
114-
* Handle size value changes, if it's allowed
52+
* Update field with mask value, if it's allowed.
11553
*
116-
* @param {String} newValue
54+
* @param {Object} placeholder
55+
* @param {Object} component
11756
*/
118-
handleSizeChanges: function (newValue) {
119-
this.values.size = newValue;
120-
this.updateValue();
121-
},
57+
updateValue: function (placeholder, component) {
58+
var string = this.mask || '',
59+
nonEmptyValueFlag = false;
12260

123-
/**
124-
* Update field value, if it's allowed
125-
*/
126-
updateValue: function () {
127-
var str = this.mask || '',
128-
nonEmptyValueFlag = false,
129-
tmpElement;
61+
if (placeholder) {
62+
this.values[placeholder] = component.getPreview() || '';
63+
}
13064

13165
if (!this.allowImport) {
13266
return;
13367
}
13468

135-
if (str) {
136-
_.each(this.values, function (propertyValue, propertyName) {
137-
str = str.replace('{{' + propertyName + '}}', propertyValue);
138-
nonEmptyValueFlag = nonEmptyValueFlag || !!propertyValue;
139-
});
140-
}
141-
142-
// strip tags
143-
tmpElement = document.createElement('div');
144-
tmpElement.innerHTML = str;
145-
str = tmpElement.textContent || tmpElement.innerText || '';
69+
_.each(this.values, function (propertyValue, propertyName) {
70+
string = string.replace('{{' + propertyName + '}}', propertyValue);
71+
nonEmptyValueFlag = nonEmptyValueFlag || !!propertyValue;
72+
});
14673

14774
if (nonEmptyValueFlag) {
148-
this.value(str);
75+
string = string.replace(/(<([^>]+)>)/ig, ''); // Remove html tags
76+
this.value(string);
77+
} else {
78+
this.value('');
14979
}
15080
},
15181

@@ -169,13 +99,20 @@ define([
16999
* and disallow/allow import value
170100
*/
171101
userChanges: function () {
102+
103+
/**
104+
* As userChanges is called before updateValue,
105+
* we forced to get value from component by reference
106+
*/
107+
var actualValue = arguments[1].currentTarget.value;
108+
172109
this._super();
173110

174-
if (this.value() === '') {
111+
if (actualValue === '') {
175112
this.allowImport = true;
176113

177114
if (this.autoImportIfEmpty) {
178-
this.updateValue();
115+
this.updateValue(null, null);
179116
}
180117
} else {
181118
this.allowImport = false;

app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ define([
5151

5252
observable() && $(el).datepicker(
5353
'setDate',
54-
moment(observable(), utils.normalizeDate(config.options.dateFormat)).toDate()
54+
moment(
55+
observable(),
56+
utils.normalizeDate(
57+
options.dateFormat + (options.showsTime ? ' ' + options.timeFormat : '')
58+
)
59+
).toDate()
5560
);
5661

5762
$(el).blur();

dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,16 @@
3434
<item name="inherit" xsi:type="number">1</item>
3535
</field>
3636
</dataset>
37+
<dataset name="attribute_product_mask_sku">
38+
<field name="catalog/fields_masks/sku" xsi:type="array">
39+
<item name="value" xsi:type="string">{{name}} {{country_of_manufacture}}</item>
40+
</field>
41+
</dataset>
42+
<dataset name="attribute_product_mask_sku_rollback">
43+
<field name="catalog/fields_masks/sku" xsi:type="array">
44+
<item name="value" xsi:type="string">{{name}}</item>
45+
<item name="inherit" xsi:type="number">1</item>
46+
</field>
47+
</dataset>
3748
</repository>
3849
</config>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Catalog\Test\TestCase\Product;
8+
9+
use Magento\Catalog\Test\Fixture\CatalogProductSimple;
10+
use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex;
11+
use Magento\Catalog\Test\Page\Adminhtml\CatalogProductNew;
12+
use Magento\Mtf\TestCase\Injectable;
13+
14+
/**
15+
* Steps:
16+
* 1. Login to the backend.
17+
* 2. Navigate to Products > Catalog.
18+
* 3. Start to create simple product.
19+
* 4. Fill in data according to data set.
20+
* 5. Save Product.
21+
* 6. Perform appropriate assertions.
22+
*
23+
* @group Products
24+
* @ZephyrId MAGETWO-59861
25+
*/
26+
class CreateSimpleProductEntityByAttributeMaskSkuTest extends Injectable
27+
{
28+
/**
29+
* Configuration setting.
30+
*
31+
* @var string
32+
*/
33+
protected $configData;
34+
35+
/**
36+
* Should cache be flushed
37+
*
38+
* @var bool
39+
*/
40+
private $flushCache;
41+
42+
/**
43+
* @var \Magento\Mtf\Fixture\FixtureFactory
44+
*/
45+
private $fixtureFactory;
46+
47+
/**
48+
* Run create product simple entity by attribute mask SKU test.
49+
*
50+
* @param CatalogProductSimple $product
51+
* @param CatalogProductIndex $productGrid
52+
* @param CatalogProductNew $newProductPage
53+
* @param string $configData
54+
* @param bool $flushCache
55+
* @return array
56+
*/
57+
public function testCreate(
58+
CatalogProductSimple $product,
59+
CatalogProductIndex $productGrid,
60+
CatalogProductNew $newProductPage,
61+
\Magento\Mtf\Fixture\FixtureFactory $fixtureFactory,
62+
$flushCache = false,
63+
$configData = null
64+
) {
65+
$this->configData = $configData;
66+
$this->flushCache = $flushCache;
67+
$this->fixtureFactory = $fixtureFactory;
68+
69+
// Preconditions
70+
$this->objectManager->create(
71+
\Magento\Config\Test\TestStep\SetupConfigurationStep::class,
72+
['configData' => $this->configData, 'flushCache' => $this->flushCache]
73+
)->run();
74+
75+
// Steps
76+
$productGrid->open();
77+
$productGrid->getGridPageActionBlock()->addProduct('simple');
78+
$newProductPage->getProductForm()->fill($product);
79+
$newProductPage->getFormPageActions()->save();
80+
81+
$skuMask = $this->prepareSkuByMask($product);
82+
83+
$productSimple = $fixtureFactory->createByCode(
84+
'catalogProductSimple',
85+
['data' => array_merge($product->getData(), ['sku' => $skuMask])]
86+
);
87+
88+
return ['product' => $productSimple];
89+
}
90+
91+
/**
92+
* Obtains product sku based on attributes define in Stores > Configuration->Catalog > Catalog > Mask for SKU
93+
*
94+
* @param CatalogProductSimple $product
95+
* @return string
96+
*/
97+
private function prepareSkuByMask(CatalogProductSimple $product)
98+
{
99+
$productData = $product->getData();
100+
$skuMask = '';
101+
$config = $this->fixtureFactory->createByCode('configData', ['dataset' => $this->configData]);
102+
$section = $config->getData('section');
103+
if (is_array($section) && array_key_exists('catalog/fields_masks/sku', $section)) {
104+
$skuMask = $section['catalog/fields_masks/sku']['value'];
105+
}
106+
107+
$attributesInPattern = [];
108+
$count = preg_match_all('/{{(\w+)}}/', $skuMask, $matches);
109+
if ($count > 0 && is_array($matches[0])) {
110+
foreach ($matches[1] as $attributeName) {
111+
if (array_key_exists($attributeName, $productData)) {
112+
$attributesInPattern[$attributeName] = $productData[$attributeName];
113+
}
114+
}
115+
}
116+
foreach ($attributesInPattern as $attributeName => $attributeValue) {
117+
$skuMask = str_replace('{{' . $attributeName . '}}', $attributeValue, $skuMask);
118+
}
119+
return $skuMask;
120+
}
121+
122+
/**
123+
* Clean data after running test.
124+
*
125+
* @return void
126+
*/
127+
public function tearDown()
128+
{
129+
$this->objectManager->create(
130+
\Magento\Config\Test\TestStep\SetupConfigurationStep::class,
131+
['configData' => $this->configData, 'rollback' => true, 'flushCache' => $this->flushCache]
132+
)->run();
133+
}
134+
}

0 commit comments

Comments
 (0)