Skip to content

Commit 3ff1430

Browse files
committed
Merge remote-tracking branches 'local/ACP2E-1175', 'local/ACP2E-1181', 'local/ACP2E-980', 'local/ACP2E-992' and 'local/ACP2E-998' into PR_15_SEP_2022_odubovyk
6 parents ef9a763 + 972fc19 + 1dda567 + 6ea8e85 + 980e8fb + 9c6ad4e commit 3ff1430

File tree

29 files changed

+812
-139
lines changed

29 files changed

+812
-139
lines changed

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

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,8 @@ public function validateUserValue($values)
9090
$option = $this->getOption();
9191
$value = $this->getUserValue();
9292

93-
if (empty($value) && $option->getIsRequire() && !$this->getSkipCheckRequiredOption()) {
94-
$this->setIsValid(false);
95-
throw new LocalizedException(
96-
__("The product's required option(s) weren't entered. Make sure the options are entered and try again.")
97-
);
98-
}
99-
if (!$this->_isSingleSelection()) {
100-
if (is_string($value)) {
101-
$value = explode(',', $value);
102-
}
103-
$valuesCollection = $option->getOptionValuesByOptionId($value, $this->getProduct()->getStoreId())->load();
104-
$valueCount = is_array($value) ? count($value) : 0;
105-
if ($valuesCollection->count() != $valueCount) {
93+
if (empty($value)) {
94+
if ($option->getIsRequire() && !$this->getSkipCheckRequiredOption()) {
10695
$this->setIsValid(false);
10796
throw new LocalizedException(
10897
__(
@@ -111,6 +100,21 @@ public function validateUserValue($values)
111100
)
112101
);
113102
}
103+
} else {
104+
if (!$this->_isSingleSelection()) {
105+
if (is_string($value)) {
106+
$value = explode(',', $value);
107+
}
108+
$valuesCollection = $option->getOptionValuesByOptionId($value, $this->getProduct()->getStoreId());
109+
$valueCount = is_array($value) ? count($value) : 0;
110+
if ($valuesCollection->count() != $valueCount) {
111+
$this->setIsValid(false);
112+
throw new LocalizedException($this->_getWrongConfigurationMessage());
113+
}
114+
} elseif (!$option->getValueById($value)) {
115+
$this->setIsValid(false);
116+
throw new LocalizedException($this->_getWrongConfigurationMessage());
117+
}
114118
}
115119
return $this;
116120
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
11+
<actionGroup name="AdminOpenAndApplyCustomOptionRecordsPerPageActionGroup">
12+
<annotations>
13+
<description>Open the custom option drop down section and assign the user defined custom value</description>
14+
</annotations>
15+
<arguments>
16+
<argument name="perPageInputValue" type="string" defaultValue="1"/>
17+
</arguments>
18+
19+
<click selector="{{AdminProductCustomOptionsPaginationSection.perPageDropdown}}" stepKey="clickProductPerPageDropdown"/>
20+
<click selector="{{AdminProductCustomOptionsPaginationSection.perPageOption('Custom')}}" stepKey="selectCustomPerPage"/>
21+
<fillField selector="{{AdminProductCustomOptionsPaginationSection.perPageInput}}" userInput="{{perPageInputValue}}" stepKey="fillCustomPerPage"/>
22+
<click selector="{{AdminProductCustomOptionsPaginationSection.perPageApplyInput}}" stepKey="applyCustomPerPage"/>
23+
<waitForPageLoad stepKey="waitForPageRefreshCustomPerPage"/>
24+
</actionGroup>
25+
</actionGroups>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
11+
<section name="AdminProductCustomOptionsPaginationSection">
12+
<element name="perPageDropdown" type="select" selector=".admin__control-table-pagination .selectmenu"/>
13+
<element name="perPageOption" type="button" selector="//div[@class='admin__control-table-pagination']//div[@class='selectmenu-items _active']//li//button[text()='{{label}}']" parameterized="true"/>
14+
<element name="perPageInput" type="input" selector="//div[@class='admin__control-table-pagination']//div[@class='selectmenu-items _active']//li[@class='_edit']//div[@class='selectmenu-item-edit']//input"/>
15+
<element name="perPageApplyInput" type="button" selector="//div[@class='admin__control-table-pagination']//div[@class='selectmenu-items _active']//li[@class='_edit']//div[@class='selectmenu-item-edit']//button"/>
16+
</section>
17+
</sections>

app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection/AdminProductCustomizableOptionsSection.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<element name="deleteCustomOptions" type="button" selector="//div[contains(@class, 'fieldset-wrapper-title')]//span[contains(., '{{optionTitle}}')]/parent::div/parent::div//button[@class='action-delete']" parameterized="true" timeout="30"/>
2323
<element name="customOption" type="block" selector="[data-index='options'] tbody tr.data-row"/>
2424
<element name="customOptionButtonDelete" type="button" selector="[data-index='options'] [data-index='delete_button']"/>
25+
<element name="toggleCustomizableOption" type="button" selector="//table[@data-index='options']//tr[{{index}}]//div[contains(@class, 'admin__collapsible-title')]" parameterized="true" timeout="30"/>
2526

2627
<element name="optionTypeDropDown" type="select" selector="//table[@data-index='options']//tr[{{index}}]//div[@data-index='type']//div[contains(@class, 'action-select-wrap')]" parameterized="true" timeout="30"/>
2728
<element name="optionTypeItem" type="select" selector="//table[@data-index='options']//tr[{{index}}]//div[@data-index='type']//*[contains(@class, 'action-menu-item')]//*[contains(., '{{optionValue}}')]" parameterized="true" timeout="30"/>
@@ -57,6 +58,13 @@
5758
<element name="optionSku" type="input" selector="//*[@data-index='custom_options']//*[@data-index='options']/tbody/tr//*[@name='product[options][{{index}}][sku]']" parameterized="true"/>
5859
<element name="optionFileExtensions" type="input" selector="//*[@data-index='custom_options']//*[@data-index='options']/tbody/tr//*[@name='product[options][{{index}}][file_extension]']" parameterized="true"/>
5960
<element name="importOptions" type="button" selector="//button[@data-index='button_import']" timeout="30"/>
61+
62+
<!-- Records/Rows Pagination -->
6063
<element name="customOptionTableRows" type="button" selector=".admin__dynamic-rows[data-index='values'] tr.data-row" timeout="30"/>
64+
<element name="customOptionsTableRecords" type="button" selector=".admin__dynamic-rows[data-index='options']>tbody>tr.data-row" timeout="30"/>
65+
66+
<!-- Elements to test drag&drop -->
67+
<element name="dragCustomOptionRecord" type="block" selector="(//tr[{{dragIndex}}]//div[contains(@class, 'draggable-handle')])['1']" timeout="30" parameterized="true"/>
68+
<element name="customOptionRecordTitle" type="button" selector="//table[@data-index='options']//tr[{{index}}]//div[contains(@class, 'admin__collapsible-title')]//span" timeout="30" parameterized="true"/>
6169
</section>
6270
</sections>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
11+
<test name="AdminValidateSimpleProductWithCustomOptionsDragNDropPerPageTest" extends="AdminValidateSimpleProductWithCustomOptionsPerPageTest">
12+
<annotations>
13+
<features value="Catalog"/>
14+
<stories value="Customizable options Drag and drop issue"/>
15+
<title value="Customizable options Drag&amp;Drop records across pages"/>
16+
<description value="Validate product's customizable option records Drag&amp;Drop functionality across pages in Admin"/>
17+
<severity value="CRITICAL"/>
18+
<testCaseId value="AC-6086"/>
19+
<useCaseId value="ACP2E-980"/>
20+
<group value="SimpleProduct"/>
21+
</annotations>
22+
23+
<!-- Create two more custom options with 2 values -->
24+
<actionGroup ref="AdminCreateCustomDropDownOptionsActionGroup" stepKey="createSecondCustomOption">
25+
<argument name="customOptionName" value="{{ProductOptionDropDown.title}}2"/>
26+
<argument name="firstOption" value="ProductOptionValueDropdown1"/>
27+
<argument name="secondOption" value="ProductOptionValueDropdown2"/>
28+
</actionGroup>
29+
30+
<scrollTo selector="{{AdminProductCustomizableOptionsSection.customizableOptions}}" stepKey="scrollToCustomOptionsSection"/>
31+
32+
<actionGroup ref="AdminCreateCustomDropDownOptionsActionGroup" stepKey="createThirdCustomOption">
33+
<argument name="customOptionName" value="{{ProductOptionDropDown.title}}3"/>
34+
<argument name="firstOption" value="ProductOptionValueDropdown1"/>
35+
<argument name="secondOption" value="ProductOptionValueDropdown2"/>
36+
</actionGroup>
37+
38+
<scrollTo selector="{{AdminProductCustomizableOptionsSection.customizableOptions}}" stepKey="scrollToCustomOptionsSection2"/>
39+
40+
<!-- Validate custom options records per page -->
41+
<actionGroup ref="AdminOpenAndApplyCustomOptionRecordsPerPageActionGroup" stepKey="decreaseNumberOfCustomOptionsPerPage">
42+
<argument name="perPageInputValue" value="1"/>
43+
</actionGroup>
44+
<waitForElementVisible selector="{{AdminProductCustomizableOptionsSection.customOptionsTableRecords}}" stepKey="waitForCustomOptionsToBeVisible"/>
45+
<seeNumberOfElements selector="{{AdminProductCustomizableOptionsSection.customOptionsTableRecords}}" userInput="1" stepKey="see1CustomOptionRecord"/>
46+
47+
<!-- Multi page Drag&Drop -->
48+
<actionGroup ref="AdminOpenAndApplyCustomOptionRecordsPerPageActionGroup" stepKey="increaseNumberOfCustomOptionsPerPage">
49+
<argument name="perPageInputValue" value="3"/>
50+
</actionGroup>
51+
<waitForElementVisible selector="{{AdminProductCustomizableOptionsSection.customOptionsTableRecords}}" stepKey="waitForCustomOptionsToBeVisible2"/>
52+
53+
<!-- Validate drag&drop -->
54+
<scrollTo selector="{{AdminProductCustomizableOptionsSection.customOptionRecordTitle('2')}}" stepKey="scrollToSeeThirdCustomOption"/>
55+
<dragAndDrop selector1="{{AdminProductCustomizableOptionsSection.dragCustomOptionRecord('3')}}" selector2="{{AdminProductCustomizableOptionsSection.dragCustomOptionRecord('2')}}" stepKey="moveCustomOptionRecord"/>
56+
<waitForPageLoad stepKey="waitForDragAndDrop"/>
57+
<see userInput="{{ProductOptionDropDown.title}}3" selector="{{AdminProductCustomizableOptionsSection.customOptionRecordTitle('2')}}" stepKey="seeCustomOptionRecord"/>
58+
59+
<!-- Prepare fore after hook -->
60+
<scrollTo selector="{{AdminProductCustomizableOptionsSection.customizableOptions}}" stepKey="scrollToCustomOptionsSection3"/>
61+
</test>
62+
</tests>

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ protected function getOptionsGridConfig($sortOrder)
372372
'config' => [
373373
'addButtonLabel' => __('Add Option'),
374374
'componentType' => DynamicRows::NAME,
375-
'component' => 'Magento_Catalog/js/components/dynamic-rows-import-custom-options',
376-
'template' => 'ui/dynamic-rows/templates/collapsible',
375+
'component' => 'Magento_Catalog/js/components/dynamic-rows-import-custom-options-per-page',
376+
'template' => 'Magento_Catalog/components/dynamic-rows-import-custom-options-per-page',
377377
'additionalClasses' => 'admin__field-wide',
378378
'deleteProperty' => static::FIELD_IS_DELETE,
379379
'deleteValue' => '1',
@@ -387,6 +387,9 @@ protected function getOptionsGridConfig($sortOrder)
387387
'insertData' => '${ $.provider }:${ $.dataProvider }',
388388
'__disableTmpl' => ['insertData' => false],
389389
],
390+
'sizesConfig' => [
391+
'enabled' => true
392+
]
390393
],
391394
],
392395
],
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
define([
7+
'Magento_Catalog/js/components/dynamic-rows-import-custom-options',
8+
'underscore',
9+
'mageUtils',
10+
'uiLayout',
11+
'rjsResolver'
12+
], function (DrCustomOptions, _, utils, layout, resolver) {
13+
'use strict';
14+
15+
return DrCustomOptions.extend({
16+
defaults: {
17+
sizesConfig: {
18+
component: 'Magento_Ui/js/grid/paging/sizes',
19+
name: '${ $.name }_sizes',
20+
options: {
21+
'20': {
22+
value: 20,
23+
label: 20
24+
},
25+
'30': {
26+
value: 30,
27+
label: 30
28+
},
29+
'50': {
30+
value: 50,
31+
label: 50
32+
},
33+
'100': {
34+
value: 100,
35+
label: 100
36+
},
37+
'200': {
38+
value: 200,
39+
label: 200
40+
}
41+
},
42+
storageConfig: {
43+
provider: '${ $.storageConfig.provider }',
44+
namespace: '${ $.storageConfig.namespace }'
45+
},
46+
enabled: false
47+
},
48+
links: {
49+
options: '${ $.sizesConfig.name }:options',
50+
pageSize: '${ $.sizesConfig.name }:value'
51+
},
52+
listens: {
53+
'pageSize': 'onPageSizeChange'
54+
},
55+
modules: {
56+
sizes: '${ $.sizesConfig.name }'
57+
}
58+
},
59+
60+
/**
61+
* Initializes paging component.
62+
*
63+
* @returns {Paging} Chainable.
64+
*/
65+
initialize: function () {
66+
this._super()
67+
.initSizes();
68+
69+
return this;
70+
},
71+
72+
/**
73+
* Initializes sizes component.
74+
*
75+
* @returns {Paging} Chainable.
76+
*/
77+
initSizes: function () {
78+
if (this.sizesConfig.enabled) {
79+
layout([this.sizesConfig]);
80+
}
81+
82+
return this;
83+
},
84+
85+
/**
86+
* Initializes observable properties.
87+
*
88+
* @returns {Paging} Chainable.
89+
*/
90+
initObservable: function () {
91+
this._super()
92+
.track([
93+
'pageSize'
94+
]);
95+
96+
return this;
97+
},
98+
99+
/**
100+
* Handles changes of the page size.
101+
*/
102+
onPageSizeChange: function () {
103+
resolver(function () {
104+
if (this.elems().length) {
105+
this.reload();
106+
}
107+
}, this);
108+
}
109+
});
110+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<!--
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
-->
7+
<div class="admin__field" css="element.setClasses(element)">
8+
<label if="element.label" class="admin__field-label" attr="for: element.uid">
9+
<span translate="element.label"></span>
10+
</label>
11+
12+
<div class="admin__field-control" data-role="grid-wrapper">
13+
<div class="admin__control-table-pagination" visible="!!element.getRecordCount()">
14+
<scope args="sizes" render=""></scope>
15+
16+
<div class="admin__data-grid-pager">
17+
<button class="action-previous" type="button" data-bind="attr: {title: $t('Previous Page')}, click: previousPage, disable: isFirst()"></button>
18+
<input class="admin__control-text" type="number" data-bind="attr: {id: ++ko.uid}, value: currentPage">
19+
<label class="admin__control-support-text" data-bind="attr: {for: ko.uid}, text: 'of ' + pages()"></label>
20+
<button class="action-next" type="button" data-bind="attr: {title: $t('Next Page')}, click: nextPage, disable: isLast()"></button>
21+
</div>
22+
</div>
23+
<table class="admin__dynamic-rows admin__control-collapsible" data-role="grid" attr="'data-index': index">
24+
25+
<thead if="element.columnsHeader">
26+
<tr data-bind="foreach: {data: labels, as: 'label'}">
27+
<th translate="label.config.label"
28+
css="item.columnsHeaderClasses">
29+
</th>
30+
</tr>
31+
</thead>
32+
33+
<tbody data-bind="foreach: elems">
34+
<tr class="data-row" data-bind="foreach: {data: elems, as: 'elem'}">
35+
<td css="$parents[1].setClasses(elem)" if="elem.template">
36+
<div class="fieldset-wrapper admin__collapsible-block-wrapper"
37+
collapsible="openClass: '_show', closeOnOuter: false, opened: elem.opened()">
38+
<div class="fieldset-wrapper-title">
39+
40+
<div class="admin__collapsible-title" data-role="collapsible-title" click="elem.toggleOpened">
41+
<render args="name: $parents[1].dndConfig.template, data: $parents[1].dnd"
42+
if="$parents[1].dndConfig.enabled" ></render>
43+
44+
<span translate="$parent.getLabel(elem)"></span>
45+
</div>
46+
47+
<button class="action-delete"
48+
data-index="delete_button"
49+
type="button"
50+
title="'Delete'"
51+
click="function(){
52+
$parents[1].deleteHandler($parent.index, $parent.recordId)
53+
}">
54+
<span translate="'Delete'"></span>
55+
</button>
56+
</div>
57+
58+
<div class="admin__collapsible-content"
59+
css="{_show: $data.opened()}"
60+
data-role="collapsible-content"
61+
template="elem.template"></div>
62+
</div>
63+
</td>
64+
</tr>
65+
</tbody>
66+
</table>
67+
68+
<div class="admin__control-table-action" if="element.addButton">
69+
<button attr="{disabled: disabled}"
70+
type="button"
71+
click="addChild.bind($data, false, false)">
72+
<span translate="addButtonLabel"></span>
73+
</button>
74+
</div>
75+
</div>
76+
</div>

0 commit comments

Comments
 (0)