Skip to content

Commit 3666e03

Browse files
🔃 [EngCom] Public Pull Requests - 2.3-develop Minor Fixes
Accepted Public Pull Requests: - #21713: Resolve Issue : Search REST API returns wrong total_count (by @ronak2ram) - #20512: Sorting by Websites not working in product grid in backoffice #20511 (by @XxXgeoXxX) - #20840: Missed form validation in Admin Order Address Edit route sales/order/address (by @XxXgeoXxX) - #20785: [Forwardport] Use batches and direct queries to fix sales address upgrade (by @ihor-sviziev) - #19859: MUI controller lacks JSON response, instead returns status 200 with empty body (by @woutersamaey) Fixed GitHub Issues: - #17295: Search REST API returns wrong total_count (reported by @mohamed-karam) has been fixed in #21713 by @ronak2ram in 2.3-develop branch Related commits: 1. 7c55811 2. a546e14 3. 9dc26cc - #20511: Sorting by 'Websites' not working in product grid in backoffice (reported by @KiraLis) has been fixed in #20512 by @XxXgeoXxX in 2.3-develop branch Related commits: 1. 0dfe0f0 2. e61b399 3. fa49579 4. 8170bd7 5. f4d1442 6. 93da772 7. 5362c5a 8. f57e5e8 9. a6f266d 10. a32d27b 11. c76d248 - #19360: Missed form validation in Admin Order Address Edit route sales/order/address (reported by @ilnytskyi) has been fixed in #20840 by @XxXgeoXxX in 2.3-develop branch Related commits: 1. 54469ce 2. 464e981 3. 7b8e969 4. fd4ed41 5. 7d6cca6 6. 8b99ea2 7. 5867a48
2 parents 931f2ea + 724e1e5 commit 3666e03

File tree

24 files changed

+747
-88
lines changed

24 files changed

+747
-88
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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="AdminSortingByWebsitesTest">
12+
<annotations>
13+
<stories value="View sorting by websites"/>
14+
<title value="Sorting by websites in Admin"/>
15+
<description value="Sorting products by websites in Admin"/>
16+
</annotations>
17+
<before>
18+
<createData entity="_defaultCategory" stepKey="createCategory"/>
19+
<createData entity="_defaultProduct" stepKey="productAssignedToCustomWebsite">
20+
<requiredEntity createDataKey="createCategory"/>
21+
</createData>
22+
<createData entity="SimpleProduct" stepKey="productAssignedToMainWebsite">
23+
<requiredEntity createDataKey="createCategory"/>
24+
</createData>
25+
26+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
27+
<!--Create new website -->
28+
<actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createAdditionalWebsite">
29+
<argument name="newWebsiteName" value="{{customWebsite.name}}"/>
30+
<argument name="websiteCode" value="{{customWebsite.code}}"/>
31+
</actionGroup>
32+
<actionGroup ref="EnableWebUrlOptions" stepKey="addStoreCodeToUrls"/>
33+
<magentoCLI command="cache:flush" stepKey="flushCacheAfterEnableWebUrlOptions"/>
34+
</before>
35+
<after>
36+
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
37+
<deleteData createDataKey="productAssignedToCustomWebsite" stepKey="deleteProductAssignedToCustomWebsite"/>
38+
<deleteData createDataKey="productAssignedToMainWebsite" stepKey="deleteProductAssignedToMainWebsite"/>
39+
<actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteTestWebsite">
40+
<argument name="websiteName" value="{{customWebsite.name}}"/>
41+
</actionGroup>
42+
<actionGroup ref="ResetWebUrlOptions" stepKey="resetUrlOption"/>
43+
<magentoCLI command="indexer:reindex" stepKey="reindex"/>
44+
<magentoCLI command="cache:flush" stepKey="flushCache"/>
45+
<actionGroup ref="logout" stepKey="logout"/>
46+
</after>
47+
48+
<!--Assign Custom Website to Simple Product -->
49+
<amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToCatalogProductGrid"/>
50+
<waitForPageLoad stepKey="waitForCatalogProductGrid"/>
51+
52+
<conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/>
53+
<actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="assignCustomWebsiteToProduct">
54+
<argument name="product" value="$$productAssignedToCustomWebsite$$"/>
55+
</actionGroup>
56+
<scrollTo selector="{{ProductInWebsitesSection.sectionHeader}}" stepKey="scrollToWebsites"/>
57+
<conditionalClick selector="{{ProductInWebsitesSection.sectionHeader}}" dependentSelector="{{AdminProductContentSection.sectionHeaderShow}}" visible="false" stepKey="expandSection"/>
58+
<waitForPageLoad stepKey="waitForPageOpened"/>
59+
<uncheckOption selector="{{ProductInWebsitesSection.website(_defaultWebsite.name)}}" stepKey="deselectMainWebsite"/>
60+
<checkOption selector="{{ProductInWebsitesSection.website(customWebsite.name)}}" stepKey="selectWebsite"/>
61+
62+
<click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSave"/>
63+
<waitForLoadingMaskToDisappear stepKey="waitForProductPageToSaveAgain"/>
64+
<seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="seeSaveProductMessageAgain"/>
65+
66+
<!--Navigate To Product Grid To Check Website Sorting-->
67+
<amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToCatalogProductGridToSortByWebsite"/>
68+
<waitForPageLoad stepKey="waitForCatalogProductGridLoaded"/>
69+
70+
<!--Sorting works (By Websites) ASC-->
71+
<click selector="{{AdminProductGridSection.columnHeader('Websites')}}" stepKey="clickWebsitesHeaderToSortAsc"/>
72+
<see selector="{{AdminProductGridSection.productGridContentsOnRow('1')}}" userInput="Main Website" stepKey="checkIfProduct1WebsitesAsc"/>
73+
74+
<!--Sorting works (By Websites) DESC-->
75+
<click selector="{{AdminProductGridSection.columnHeader('Websites')}}" stepKey="clickWebsitesHeaderToSortDesc"/>
76+
<see selector="{{AdminProductGridSection.productGridContentsOnRow('1')}}" userInput="{{customWebsite.name}}" stepKey="checkIfProduct1WebsitesDesc"/>
77+
</test>
78+
</tests>

app/code/Magento/Catalog/Ui/Component/Listing/Columns/Websites.php

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
7+
declare(strict_types=1);
8+
69
namespace Magento\Catalog\Ui\Component\Listing\Columns;
710

8-
use Magento\Framework\View\Element\UiComponentFactory;
11+
use Magento\Framework\DB\Helper;
912
use Magento\Framework\View\Element\UiComponent\ContextInterface;
13+
use Magento\Framework\View\Element\UiComponentFactory;
1014
use Magento\Store\Model\StoreManagerInterface;
1115

1216
/**
17+
* Websites listing column component.
18+
*
1319
* @api
1420
* @since 100.0.2
1521
*/
@@ -20,33 +26,48 @@ class Websites extends \Magento\Ui\Component\Listing\Columns\Column
2026
*/
2127
const NAME = 'websites';
2228

29+
/**
30+
* Data for concatenated website names value.
31+
*/
32+
private $websiteNames = 'website_names';
33+
2334
/**
2435
* Store manager
2536
*
2637
* @var StoreManagerInterface
2738
*/
2839
protected $storeManager;
2940

41+
/**
42+
* @var \Magento\Framework\DB\Helper
43+
*/
44+
private $resourceHelper;
45+
3046
/**
3147
* @param ContextInterface $context
3248
* @param UiComponentFactory $uiComponentFactory
3349
* @param StoreManagerInterface $storeManager
3450
* @param array $components
3551
* @param array $data
52+
* @param Helper $resourceHelper
3653
*/
3754
public function __construct(
3855
ContextInterface $context,
3956
UiComponentFactory $uiComponentFactory,
4057
StoreManagerInterface $storeManager,
4158
array $components = [],
42-
array $data = []
59+
array $data = [],
60+
Helper $resourceHelper = null
4361
) {
4462
parent::__construct($context, $uiComponentFactory, $components, $data);
63+
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
4564
$this->storeManager = $storeManager;
65+
$this->resourceHelper = $resourceHelper ?: $objectManager->get(Helper::class);
4666
}
4767

4868
/**
49-
* {@inheritdoc}
69+
* @inheritdoc
70+
*
5071
* @deprecated 101.0.0
5172
*/
5273
public function prepareDataSource(array $dataSource)
@@ -71,9 +92,10 @@ public function prepareDataSource(array $dataSource)
7192

7293
return $dataSource;
7394
}
74-
95+
7596
/**
76-
* Prepare component configuration
97+
* Prepare component configuration.
98+
*
7799
* @return void
78100
*/
79101
public function prepare()
@@ -83,4 +105,46 @@ public function prepare()
83105
$this->_data['config']['componentDisabled'] = true;
84106
}
85107
}
108+
109+
/**
110+
* Apply sorting.
111+
*
112+
* @return void
113+
*/
114+
protected function applySorting()
115+
{
116+
$sorting = $this->getContext()->getRequestParam('sorting');
117+
$isSortable = $this->getData('config/sortable');
118+
if ($isSortable !== false
119+
&& !empty($sorting['field'])
120+
&& !empty($sorting['direction'])
121+
&& $sorting['field'] === $this->getName()
122+
) {
123+
$collection = $this->getContext()->getDataProvider()->getCollection();
124+
$collection
125+
->joinField(
126+
'websites_ids',
127+
'catalog_product_website',
128+
'website_id',
129+
'product_id=entity_id',
130+
null,
131+
'left'
132+
)
133+
->joinTable(
134+
'store_website',
135+
'website_id = websites_ids',
136+
['name'],
137+
null,
138+
'left'
139+
)
140+
->groupByAttribute('entity_id');
141+
$this->resourceHelper->addGroupConcatColumn(
142+
$collection->getSelect(),
143+
$this->websiteNames,
144+
'name'
145+
);
146+
147+
$collection->getSelect()->order($this->websiteNames . ' ' . $sorting['direction']);
148+
}
149+
}
86150
}

app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@
4646
<data key="website_id">0</data>
4747
<requiredEntity type="address">US_Address_TX</requiredEntity>
4848
</entity>
49+
<entity name="Simple_US_Customer_Incorrect_Name" type="customer">
50+
<data key="group_id">1</data>
51+
<data key="default_billing">true</data>
52+
<data key="default_shipping">true</data>
53+
<data key="email" unique="prefix">[email protected]</data>
54+
<data key="firstname">LoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsum</data>
55+
<data key="lastname">Doe</data>
56+
<data key="fullname">John Doe</data>
57+
<data key="password">pwdTest123!</data>
58+
<data key="store_id">0</data>
59+
<data key="website_id">0</data>
60+
<requiredEntity type="address">US_Address_TX</requiredEntity>
61+
</entity>
4962
<entity name="Simple_Customer_Without_Address" type="customer">
5063
<data key="group_id">1</data>
5164
<data key="email" unique="prefix">[email protected]</data>
@@ -190,4 +203,4 @@
190203
<data key="store_id">0</data>
191204
<data key="website_id">0</data>
192205
</entity>
193-
</entities>
206+
</entities>

app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/AbstractForm.php

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\Sales\Block\Adminhtml\Order\Create\Form;
77

88
use Magento\Framework\Pricing\PriceCurrencyInterface;
9+
use Magento\Customer\Api\Data\AttributeMetadataInterface;
910

1011
/**
1112
* Sales Order Create Form Abstract Block
@@ -57,8 +58,7 @@ public function __construct(
5758
}
5859

5960
/**
60-
* Prepare global layout
61-
* Add renderers to \Magento\Framework\Data\Form
61+
* Prepare global layout. Add renderers to \Magento\Framework\Data\Form
6262
*
6363
* @return $this
6464
*/
@@ -152,7 +152,7 @@ protected function _addAdditionalFormElementData(\Magento\Framework\Data\Form\El
152152
/**
153153
* Add rendering EAV attributes to Form element
154154
*
155-
* @param \Magento\Customer\Api\Data\AttributeMetadataInterface[] $attributes
155+
* @param AttributeMetadataInterface[] $attributes
156156
* @param \Magento\Framework\Data\Form\AbstractForm $form
157157
* @return $this
158158
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
@@ -176,8 +176,8 @@ protected function _addAttributesToForm($attributes, \Magento\Framework\Data\For
176176
[
177177
'name' => $attribute->getAttributeCode(),
178178
'label' => __($attribute->getStoreLabel()),
179-
'class' => $attribute->getFrontendClass(),
180-
'required' => $attribute->isRequired()
179+
'class' => $this->getValidationClasses($attribute),
180+
'required' => $attribute->isRequired(),
181181
]
182182
);
183183
if ($inputType == 'multiline') {
@@ -227,4 +227,58 @@ public function getFormValues()
227227
{
228228
return [];
229229
}
230+
231+
/**
232+
* Retrieve frontend classes according validation rules
233+
*
234+
* @param AttributeMetadataInterface $attribute
235+
*
236+
* @return string
237+
*/
238+
private function getValidationClasses(AttributeMetadataInterface $attribute) : string
239+
{
240+
$out = [];
241+
$out[] = $attribute->getFrontendClass();
242+
243+
$textClasses = $this->getTextLengthValidateClasses($attribute);
244+
if (!empty($textClasses)) {
245+
$out = array_merge($out, $textClasses);
246+
}
247+
248+
$out = !empty($out) ? implode(' ', array_unique(array_filter($out))) : '';
249+
return $out;
250+
}
251+
252+
/**
253+
* Retrieve validation classes by min_text_length and max_text_length rules
254+
*
255+
* @param AttributeMetadataInterface $attribute
256+
*
257+
* @return array
258+
*/
259+
private function getTextLengthValidateClasses(AttributeMetadataInterface $attribute) : array
260+
{
261+
$classes = [];
262+
263+
$validateRules = $attribute->getValidationRules();
264+
if (!empty($validateRules)) {
265+
foreach ($validateRules as $rule) {
266+
switch ($rule->getName()) {
267+
case 'min_text_length':
268+
$classes[] = 'minimum-length-' . $rule->getValue();
269+
break;
270+
271+
case 'max_text_length':
272+
$classes[] = 'maximum-length-' . $rule->getValue();
273+
break;
274+
}
275+
}
276+
277+
if (!empty($classes)) {
278+
$classes[] = 'validate-length';
279+
}
280+
}
281+
282+
return $classes;
283+
}
230284
}

0 commit comments

Comments
 (0)