Skip to content

Commit fce7c72

Browse files
committed
Merge remote-tracking branch 'github-magento2ce/MAGETWO-91633' into EPAM-PR-18
2 parents dce4b70 + 40b2ebb commit fce7c72

File tree

7 files changed

+526
-7
lines changed

7 files changed

+526
-7
lines changed

app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,9 @@
1111
<section name="AdminProductFormGroupedProductsSection">
1212
<element name="toggleGroupedProduct" type="button" selector="div[data-index=grouped] .admin__collapsible-title"/>
1313
<element name="addProductsToGroup" type="button" selector="button[data-index='grouped_products_button']" timeout="30"/>
14+
<element name="nextActionButton" type="button" selector="//*[@data-index='grouped']//*[@class='action-next']"/>
15+
<element name="previousActionButton" type="button" selector="//*[@data-index='grouped']//*[@class='action-previous']"/>
16+
<element name="positionProduct" type="input" selector="//tbody/tr[{{arg}}][contains(@class,'data-row')]/td[10]//input[@class='position-widget-input']" parameterized="true"/>
17+
<element name="nameProductFromGrid" type="text" selector="//tbody/tr[{{arg}}][contains(@class,'data-row')]/td[4]//*[@class='admin__field-control']//span" parameterized="true"/>
1418
</section>
15-
</sections>
19+
</sections>
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
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="AdminSortingAssociatedProductsTest">
12+
<annotations>
13+
<features value="GroupedProduct"/>
14+
<stories value="MAGETWO-91633: Grouped Products: Associated Products Can't Be Sorted Between Pages"/>
15+
<title value="Grouped Products: Sorting Associated Products Between Pages"/>
16+
<description value="Make sure that products in grid were recalculated when sorting associated products between pages"/>
17+
<severity value="MAJOR"/>
18+
<testCaseId value="MAGETWO-95085"/>
19+
<group value="GroupedProduct"/>
20+
</annotations>
21+
<before>
22+
<actionGroup ref="LoginAsAdmin" stepKey="login"/>
23+
<createData entity="_defaultCategory" stepKey="category"/>
24+
<!-- Create 23 products so that grid can have more than one page -->
25+
<createData entity="ApiSimpleProduct" stepKey="product1">
26+
<requiredEntity createDataKey="category"/>
27+
</createData>
28+
<createData entity="ApiSimpleProduct" stepKey="product2">
29+
<requiredEntity createDataKey="category"/>
30+
</createData>
31+
<createData entity="ApiSimpleProduct" stepKey="product3">
32+
<requiredEntity createDataKey="category"/>
33+
</createData>
34+
<createData entity="ApiSimpleProduct" stepKey="product4">
35+
<requiredEntity createDataKey="category"/>
36+
</createData>
37+
<createData entity="ApiSimpleProduct" stepKey="product5">
38+
<requiredEntity createDataKey="category"/>
39+
</createData>
40+
<createData entity="ApiSimpleProduct" stepKey="product6">
41+
<requiredEntity createDataKey="category"/>
42+
</createData>
43+
<createData entity="ApiSimpleProduct" stepKey="product7">
44+
<requiredEntity createDataKey="category"/>
45+
</createData>
46+
<createData entity="ApiSimpleProduct" stepKey="product8">
47+
<requiredEntity createDataKey="category"/>
48+
</createData>
49+
<createData entity="ApiSimpleProduct" stepKey="product9">
50+
<requiredEntity createDataKey="category"/>
51+
</createData>
52+
<createData entity="ApiSimpleProduct" stepKey="product10">
53+
<requiredEntity createDataKey="category"/>
54+
</createData>
55+
<createData entity="ApiSimpleProduct" stepKey="product11">
56+
<requiredEntity createDataKey="category"/>
57+
</createData>
58+
<createData entity="ApiSimpleProduct" stepKey="product12">
59+
<requiredEntity createDataKey="category"/>
60+
</createData>
61+
<createData entity="ApiSimpleProduct" stepKey="product13">
62+
<requiredEntity createDataKey="category"/>
63+
</createData>
64+
<createData entity="ApiSimpleProduct" stepKey="product14">
65+
<requiredEntity createDataKey="category"/>
66+
</createData>
67+
<createData entity="ApiSimpleProduct" stepKey="product15">
68+
<requiredEntity createDataKey="category"/>
69+
</createData>
70+
<createData entity="ApiSimpleProduct" stepKey="product16">
71+
<requiredEntity createDataKey="category"/>
72+
</createData>
73+
<createData entity="ApiSimpleProduct" stepKey="product17">
74+
<requiredEntity createDataKey="category"/>
75+
</createData>
76+
<createData entity="ApiSimpleProduct" stepKey="product18">
77+
<requiredEntity createDataKey="category"/>
78+
</createData>
79+
<createData entity="ApiSimpleProduct" stepKey="product19">
80+
<requiredEntity createDataKey="category"/>
81+
</createData>
82+
<createData entity="ApiSimpleProduct" stepKey="product20">
83+
<requiredEntity createDataKey="category"/>
84+
</createData>
85+
<createData entity="ApiSimpleProduct" stepKey="product21">
86+
<requiredEntity createDataKey="category"/>
87+
</createData>
88+
<createData entity="ApiSimpleProduct" stepKey="product22">
89+
<requiredEntity createDataKey="category"/>
90+
</createData>
91+
<createData entity="ApiSimpleProduct" stepKey="product23">
92+
<requiredEntity createDataKey="category"/>
93+
</createData>
94+
</before>
95+
<after>
96+
<!--Delete created grouped product-->
97+
<actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteProduct">
98+
<argument name="product" value="GroupedProduct"/>
99+
</actionGroup>
100+
<conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}"
101+
dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/>
102+
<deleteData createDataKey="product1" stepKey="deleteProduct1"/>
103+
<deleteData createDataKey="product2" stepKey="deleteProduct2"/>
104+
<deleteData createDataKey="product3" stepKey="deleteProduct3"/>
105+
<deleteData createDataKey="product4" stepKey="deleteProduct4"/>
106+
<deleteData createDataKey="product5" stepKey="deleteProduct5"/>
107+
<deleteData createDataKey="product6" stepKey="deleteProduct6"/>
108+
<deleteData createDataKey="product7" stepKey="deleteProduct7"/>
109+
<deleteData createDataKey="product8" stepKey="deleteProduct8"/>
110+
<deleteData createDataKey="product9" stepKey="deleteProduct9"/>
111+
<deleteData createDataKey="product10" stepKey="deleteProduct10"/>
112+
<deleteData createDataKey="product11" stepKey="deleteProduct11"/>
113+
<deleteData createDataKey="product12" stepKey="deleteProduct12"/>
114+
<deleteData createDataKey="product13" stepKey="deleteProduct13"/>
115+
<deleteData createDataKey="product14" stepKey="deleteProduct14"/>
116+
<deleteData createDataKey="product15" stepKey="deleteProduct15"/>
117+
<deleteData createDataKey="product16" stepKey="deleteProduct16"/>
118+
<deleteData createDataKey="product17" stepKey="deleteProduct17"/>
119+
<deleteData createDataKey="product18" stepKey="deleteProduct18"/>
120+
<deleteData createDataKey="product19" stepKey="deleteProduct19"/>
121+
<deleteData createDataKey="product20" stepKey="deleteProduct20"/>
122+
<deleteData createDataKey="product21" stepKey="deleteProduct21"/>
123+
<deleteData createDataKey="product22" stepKey="deleteProduct22"/>
124+
<deleteData createDataKey="product23" stepKey="deleteProduct23"/>
125+
<deleteData createDataKey="category" stepKey="deleteCategory"/>
126+
<actionGroup ref="logout" stepKey="logout"/>
127+
</after>
128+
129+
<!--Create grouped Product-->
130+
<amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/>
131+
<waitForPageLoad stepKey="waitForProductIndexPage"/>
132+
<actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/>
133+
<actionGroup ref="goToCreateProductPage" stepKey="goToCreateProduct">
134+
<argument name="product" value="GroupedProduct"/>
135+
</actionGroup>
136+
<actionGroup ref="fillGroupedProductForm" stepKey="fillProductForm">
137+
<argument name="product" value="GroupedProduct"/>
138+
</actionGroup>
139+
140+
<scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToGroupedSection"/>
141+
<conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductsSection"/>
142+
<click selector="body" stepKey="clickBodyToCorrectFocusGrouped"/>
143+
<click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroup"/>
144+
<waitForElementVisible selector="{{AdminAddProductsToGroupPanel.filters}}" stepKey="waitForGroupedProductModal"/>
145+
<actionGroup ref="filterProductGridBySku2" stepKey="filterGroupedProducts">
146+
<argument name="sku" value="api-simple-product"/>
147+
</actionGroup>
148+
149+
<!-- Select all, then start the bulk update attributes flow -->
150+
<click selector="{{AdminProductGridSection.multicheckDropdown}}" stepKey="openMulticheckDropdown"/>
151+
<click selector="{{AdminProductGridSection.multicheckOption('Select All')}}" stepKey="selectAllProductInFilteredGrid"/>
152+
153+
<click selector="{{AdminAddProductsToGroupPanel.addSelectedProducts}}" stepKey="clickAddSelectedGroupProducts"/>
154+
<waitForPageLoad stepKey="waitForProductsAdded"/>
155+
156+
<actionGroup ref="saveProductForm" stepKey="saveProduct"/>
157+
158+
<!--Open created Product group-->
159+
<amOnPage url="{{AdminProductIndexPage.url}}" stepKey="goToProductIndex"/>
160+
<waitForPageLoad stepKey="waitForProductIndexPageLoad"/>
161+
<actionGroup ref="resetProductGridToDefaultView" stepKey="resetFiltersIfExist"/>
162+
<actionGroup ref="searchProductGridByKeyword" stepKey="searchProductGridForm">
163+
<argument name="keyword" value="GroupedProduct.name"/>
164+
</actionGroup>
165+
<click selector="{{AdminProductGridSection.selectRowBasedOnName(GroupedProduct.name)}}" stepKey="openGroupedProduct"/>
166+
<waitForPageLoad stepKey="waitForProductEditPageLoad"/>
167+
168+
<scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToGroupedSection2"/>
169+
<conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductsSection2"/>
170+
171+
<!--Change position value for the Product Position 0-->
172+
<grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('1')}}" stepKey="grabNameProductPosition0"/>
173+
<grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('2')}}" stepKey="grabNameProductPositionFirst"/>
174+
<fillField selector="{{AdminProductFormGroupedProductsSection.positionProduct('1')}}" userInput="21" stepKey="fillFieldProductPosition0"/>
175+
<doubleClick selector="{{AdminProductFormGroupedProductsSection.nextActionButton}}" stepKey="clickButton"/>
176+
<waitForAjaxLoad stepKey="waitForAjax1"/>
177+
178+
<!--Go to next page and verify that Products in grid were recalculated-->
179+
<doubleClick selector="{{AdminProductFormGroupedProductsSection.nextActionButton}}" stepKey="clickNextActionButton"/>
180+
<waitForAjaxLoad stepKey="waitForAjax2"/>
181+
182+
<grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('2')}}" stepKey="grabNameProductPosition21"/>
183+
<assertEquals stepKey="assertProductsRecalculated">
184+
<actualResult type="string">$grabNameProductPosition0</actualResult>
185+
<expectedResult type="string">$grabNameProductPosition21</expectedResult>
186+
</assertEquals>
187+
188+
<!--Change position value for the product to 1-->
189+
<fillField selector="{{AdminProductFormGroupedProductsSection.positionProduct('2')}}" userInput="1" stepKey="fillFieldProductPosition1"/>
190+
<doubleClick selector="{{AdminProductFormGroupedProductsSection.previousActionButton}}" stepKey="clickButton2"/>
191+
<waitForAjaxLoad stepKey="waitForAjax3"/>
192+
193+
<!--Go to previous page and verify that Products in grid were recalculated-->
194+
<click selector="{{AdminProductFormGroupedProductsSection.previousActionButton}}" stepKey="clickPreviousActionButton"/>
195+
<waitForAjaxLoad stepKey="waitForAjax4"/>
196+
<grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('2')}}" stepKey="grabNameProductPosition2"/>
197+
<grabTextFrom selector="{{AdminProductFormGroupedProductsSection.nameProductFromGrid('1')}}" stepKey="grabNameProductPositionZero"/>
198+
<assertEquals stepKey="assertProductsRecalculated2">
199+
<actualResult type="string">$grabNameProductPosition2</actualResult>
200+
<expectedResult type="string">$grabNameProductPosition0</expectedResult>
201+
</assertEquals>
202+
<assertEquals stepKey="assertProductsRecalculated3">
203+
<actualResult type="string">$grabNameProductPositionFirst</actualResult>
204+
<expectedResult type="string">$grabNameProductPositionZero</expectedResult>
205+
</assertEquals>
206+
</test>
207+
</tests>

app/code/Magento/GroupedProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GroupedTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class GroupedTest extends AbstractModifierTest
3434
const LINKED_PRODUCT_NAME = 'linked';
3535
const LINKED_PRODUCT_QTY = '0';
3636
const LINKED_PRODUCT_POSITION = 1;
37+
const LINKED_PRODUCT_POSITION_CALCULATED = 1;
3738
const LINKED_PRODUCT_PRICE = '1';
3839

3940
/**
@@ -212,6 +213,7 @@ public function testModifyData()
212213
'price' => null,
213214
'qty' => self::LINKED_PRODUCT_QTY,
214215
'position' => self::LINKED_PRODUCT_POSITION,
216+
'positionCalculated' => self::LINKED_PRODUCT_POSITION_CALCULATED,
215217
'thumbnail' => null,
216218
'type_id' => null,
217219
'status' => null,

app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ public function __construct(
133133
}
134134

135135
/**
136-
* {@inheritdoc}
136+
* @inheritdoc
137137
*/
138138
public function modifyData(array $data)
139139
{
@@ -143,12 +143,17 @@ public function modifyData(array $data)
143143
if ($modelId) {
144144
$storeId = $this->locator->getStore()->getId();
145145
$data[$product->getId()]['links'][self::LINK_TYPE] = [];
146-
foreach ($this->productLinkRepository->getList($product) as $linkItem) {
146+
$linkedItems = $this->productLinkRepository->getList($product);
147+
usort($linkedItems, function ($a, $b) {
148+
return $a->getPosition() <=> $b->getPosition();
149+
});
150+
foreach ($linkedItems as $index => $linkItem) {
147151
if ($linkItem->getLinkType() !== self::LINK_TYPE) {
148152
continue;
149153
}
150154
/** @var \Magento\Catalog\Api\Data\ProductInterface $linkedProduct */
151155
$linkedProduct = $this->productRepository->get($linkItem->getLinkedProductSku(), false, $storeId);
156+
$linkItem->setPosition($index);
152157
$data[$modelId]['links'][self::LINK_TYPE][] = $this->fillData($linkedProduct, $linkItem);
153158
}
154159
$data[$modelId][self::DATA_SOURCE_DEFAULT]['current_store_id'] = $storeId;
@@ -175,6 +180,7 @@ protected function fillData(ProductInterface $linkedProduct, ProductLinkInterfac
175180
'price' => $currency->toCurrency(sprintf("%f", $linkedProduct->getPrice())),
176181
'qty' => $linkItem->getExtensionAttributes()->getQty(),
177182
'position' => $linkItem->getPosition(),
183+
'positionCalculated' => $linkItem->getPosition(),
178184
'thumbnail' => $this->imageHelper->init($linkedProduct, 'product_listing_thumbnail')->getUrl(),
179185
'type_id' => $linkedProduct->getTypeId(),
180186
'status' => $this->status->getOptionText($linkedProduct->getStatus()),
@@ -185,7 +191,7 @@ protected function fillData(ProductInterface $linkedProduct, ProductLinkInterfac
185191
}
186192

187193
/**
188-
* {@inheritdoc}
194+
* @inheritdoc
189195
*/
190196
public function modifyMeta(array $meta)
191197
{
@@ -454,7 +460,7 @@ protected function getGrid()
454460
'label' => null,
455461
'renderDefaultRecord' => false,
456462
'template' => 'ui/dynamic-rows/templates/grid',
457-
'component' => 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid',
463+
'component' => 'Magento_GroupedProduct/js/grouped-product-grid',
458464
'addButton' => false,
459465
'itemTemplate' => 'record',
460466
'dataScope' => 'data.links',
@@ -555,6 +561,22 @@ protected function fillMeta()
555561
],
556562
],
557563
],
564+
'positionCalculated' => [
565+
'arguments' => [
566+
'data' => [
567+
'config' => [
568+
'label' => __('Position'),
569+
'dataType' => Form\Element\DataType\Number::NAME,
570+
'formElement' => Form\Element\Input::NAME,
571+
'componentType' => Form\Field::NAME,
572+
'elementTmpl' => 'Magento_GroupedProduct/components/position',
573+
'sortOrder' => 90,
574+
'fit' => true,
575+
'dataScope' => 'positionCalculated'
576+
],
577+
],
578+
],
579+
],
558580
'actionDelete' => [
559581
'arguments' => [
560582
'data' => [
@@ -563,7 +585,7 @@ protected function fillMeta()
563585
'componentType' => 'actionDelete',
564586
'dataType' => Form\Element\DataType\Text::NAME,
565587
'label' => __('Actions'),
566-
'sortOrder' => 90,
588+
'sortOrder' => 100,
567589
'fit' => true,
568590
],
569591
],
@@ -577,7 +599,7 @@ protected function fillMeta()
577599
'formElement' => Form\Element\Input::NAME,
578600
'componentType' => Form\Field::NAME,
579601
'dataScope' => 'position',
580-
'sortOrder' => 100,
602+
'sortOrder' => 110,
581603
'visible' => false,
582604
],
583605
],

app/code/Magento/GroupedProduct/view/adminhtml/web/css/grouped-product.css

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,49 @@
6666
overflow: hidden;
6767
text-overflow: ellipsis;
6868
}
69+
70+
.position {
71+
width: 100px;
72+
}
73+
74+
.icon-rearrange-position > span {
75+
border: 0;
76+
clip: rect(0, 0, 0, 0);
77+
height: 1px;
78+
margin: -1px;
79+
overflow: hidden;
80+
padding: 0;
81+
position: absolute;
82+
width: 1px;
83+
}
84+
85+
.icon-forward,
86+
.icon-backward {
87+
-webkit-font-smoothing: antialiased;
88+
font-family: 'Admin Icons';
89+
font-size: 17px;
90+
speak: none;
91+
}
92+
93+
.position > * {
94+
float: left;
95+
margin: 3px;
96+
}
97+
98+
.position-widget-input {
99+
text-align: center;
100+
width: 40px;
101+
}
102+
103+
.icon-forward:before {
104+
content: '\e618';
105+
}
106+
107+
.icon-backward:before {
108+
content: '\e619';
109+
}
110+
111+
.icon-rearrange-position, .icon-rearrange-position:hover {
112+
color: #d9d9d9;
113+
text-decoration: none;
114+
}

0 commit comments

Comments
 (0)