Skip to content

Commit 90334d9

Browse files
committed
MC-41796: Adding Date/Time attribute results to an error with Mass Action
- Fix datetime attribute is causing error on mass update attributes page
1 parent 9d1fe17 commit 90334d9

File tree

6 files changed

+167
-17
lines changed

6 files changed

+167
-17
lines changed

app/code/Magento/Backend/Block/Widget/Form.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ protected function _applyTypeSpecificConfig($inputType, $element, \Magento\Eav\M
230230
case 'date':
231231
$element->setDateFormat($this->_localeDate->getDateFormatWithLongYear());
232232
break;
233+
case 'datetime':
234+
$element->setDateFormat($this->_localeDate->getDateFormatWithLongYear());
235+
$element->setTimeFormat($this->_localeDate->getTimeFormat());
236+
break;
233237
case 'multiline':
234238
$element->setLineCount($attribute->getMultilineCount());
235239
break;
@@ -246,7 +250,13 @@ protected function _applyTypeSpecificConfig($inputType, $element, \Magento\Eav\M
246250
*/
247251
protected function _addElementTypes(\Magento\Framework\Data\Form\AbstractForm $baseElement)
248252
{
249-
$types = $this->_getAdditionalElementTypes();
253+
$types = array_merge(
254+
[
255+
'datetime' => 'date'
256+
],
257+
$this->_getAdditionalElementTypes()
258+
);
259+
250260
foreach ($types as $code => $className) {
251261
$baseElement->addType($code, $className);
252262
}

app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
namespace Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute;
88

99
use Magento\AsynchronousOperations\Api\Data\OperationInterface;
10+
use Magento\Catalog\Model\Product\Filter\DateTime as DateTimeFilter;
1011
use Magento\Catalog\Model\ProductFactory;
1112
use Magento\Catalog\Api\Data\ProductAttributeInterface;
1213
use Magento\Eav\Model\Config;
1314
use Magento\Framework\App\Action\HttpPostActionInterface;
1415
use Magento\Backend\App\Action;
1516
use Magento\Framework\App\ObjectManager;
1617
use Magento\Framework\Exception\LocalizedException;
18+
use Magento\Framework\Stdlib\DateTime;
1719
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
1820

1921
/**
@@ -67,6 +69,11 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribut
6769
*/
6870
private $productFactory;
6971

72+
/**
73+
* @var DateTimeFilter
74+
*/
75+
private $dateTimeFilter;
76+
7077
/**
7178
* @param Action\Context $context
7279
* @param \Magento\Catalog\Helper\Product\Edit\Action\Attribute $attributeHelper
@@ -76,9 +83,10 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribut
7683
* @param \Magento\Framework\Serialize\SerializerInterface $serializer
7784
* @param \Magento\Authorization\Model\UserContextInterface $userContext
7885
* @param int $bulkSize
79-
* @param TimezoneInterface $timezone
80-
* @param Config $eavConfig
81-
* @param ProductFactory $productFactory
86+
* @param TimezoneInterface|null $timezone
87+
* @param Config|null $eavConfig
88+
* @param ProductFactory|null $productFactory
89+
* @param DateTimeFilter|null $dateTimeFilter
8290
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
8391
*/
8492
public function __construct(
@@ -92,7 +100,8 @@ public function __construct(
92100
int $bulkSize = 100,
93101
TimezoneInterface $timezone = null,
94102
Config $eavConfig = null,
95-
ProductFactory $productFactory = null
103+
ProductFactory $productFactory = null,
104+
?DateTimeFilter $dateTimeFilter = null
96105
) {
97106
parent::__construct($context, $attributeHelper);
98107
$this->bulkManagement = $bulkManagement;
@@ -106,6 +115,7 @@ public function __construct(
106115
$this->eavConfig = $eavConfig ?: ObjectManager::getInstance()
107116
->get(Config::class);
108117
$this->productFactory = $productFactory ?? ObjectManager::getInstance()->get(ProductFactory::class);
118+
$this->dateTimeFilter = $dateTimeFilter ?? ObjectManager::getInstance()->get(DateTimeFilter::class);
109119
}
110120

111121
/**
@@ -155,8 +165,6 @@ public function execute()
155165
*/
156166
private function sanitizeProductAttributes($attributesData)
157167
{
158-
$dateFormat = $this->timezone->getDateFormat(\IntlDateFormatter::SHORT);
159-
160168
foreach ($attributesData as $attributeCode => $value) {
161169
if ($attributeCode === ProductAttributeInterface::CODE_HAS_WEIGHT) {
162170
continue;
@@ -170,16 +178,10 @@ private function sanitizeProductAttributes($attributesData)
170178
}
171179

172180
if ($attribute->getBackendType() === 'datetime') {
173-
if (!empty($value)) {
174-
$filterInput = new \Zend_Filter_LocalizedToNormalized(['date_format' => $dateFormat]);
175-
$filterInternal = new \Zend_Filter_NormalizedToLocalized(
176-
['date_format' => \Magento\Framework\Stdlib\DateTime::DATE_INTERNAL_FORMAT]
177-
);
178-
$value = $filterInternal->filter($filterInput->filter($value));
179-
} else {
180-
$value = null;
181-
}
182-
$attributesData[$attributeCode] = $value;
181+
$attributesData[$attributeCode] = $this->filterDate(
182+
$value,
183+
$attribute->getFrontendInput() === 'datetime'
184+
);
183185
} elseif ($attribute->getFrontendInput() === 'multiselect') {
184186
// Check if 'Change' checkbox has been checked by admin for this attribute
185187
$isChanged = (bool)$this->getRequest()->getPost('toggle_' . $attributeCode);
@@ -196,6 +198,24 @@ private function sanitizeProductAttributes($attributesData)
196198
return $attributesData;
197199
}
198200

201+
/**
202+
* Get the date and time value in internal format and timezone
203+
*
204+
* @param string $value
205+
* @param bool $isDatetime
206+
* @return string|null
207+
* @throws LocalizedException
208+
*/
209+
private function filterDate(string $value, bool $isDatetime = false): ?string
210+
{
211+
$date = !empty($value) ? $this->dateTimeFilter->filter($value) : null;
212+
if ($date && $isDatetime) {
213+
$date = $this->timezone->convertConfigTimeToUtc($date, DateTime::DATETIME_PHP_FORMAT);
214+
}
215+
216+
return $date;
217+
}
218+
199219
/**
200220
* Validate product attributes data.
201221
*
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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="AdminMassUpdateProductAttributeActionGroup">
12+
<arguments>
13+
<argument name="attributeCode" type="string" defaultValue="{{newProductAttribute.attribute_code}}"/>
14+
<argument name="attributeValue" type="string" defaultValue=""/>
15+
</arguments>
16+
<checkOption selector="{{AdminEditProductAttributesSection.toggleAttribute(attributeCode)}}" stepKey="toggleAttribute"/>
17+
<fillField selector="{{AdminEditProductAttributesSection.attributeInput(attributeCode)}}" userInput="{{attributeValue}}" stepKey="setAttributeValue"/>
18+
</actionGroup>
19+
</actionGroups>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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="AdminMassUpdateProductAttributeSaveActionGroup">
12+
<click selector="{{AdminUpdateAttributesSection.saveButton}}" stepKey="save"/>
13+
<waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitVisibleSuccessMessage"/>
14+
<see selector="{{AdminMessagesSection.success}}" userInput="Message is added to queue" stepKey="seeSuccessMessage"/>
15+
</actionGroup>
16+
</actionGroups>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,7 @@
2525
<element name="tabButton" type="text" selector="#product_attribute_tabs a[title='{{tabName}}']" parameterized="true"/>
2626
<element name="attributeShortDescription" type="text" selector="#short_description"/>
2727
<element name="changeAttributeShortDescriptionToggle" type="checkbox" selector="#toggle_short_description"/>
28+
<element name="attributeInput" type="input" selector="#{{attributeCode}}" parameterized="true"/>
29+
<element name="toggleAttribute" type="checkbox" selector="#toggle_{{attributeCode}}" parameterized="true"/>
2830
</section>
2931
</sections>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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="AdminMassUpdateProductAttributeDatetimeTest">
12+
<annotations>
13+
<features value="Catalog"/>
14+
<stories value="Mass update product attributes"/>
15+
<title value="Admin should be able to mass update datetime attribute"/>
16+
<description value="Admin should be able to mass update datetime attribute"/>
17+
<severity value="AVERAGE"/>
18+
<testCaseId value="MC-41972"/>
19+
<useCaseId value="MC-41796"/>
20+
<group value="catalog"/>
21+
<group value="product_attributes"/>
22+
</annotations>
23+
<before>
24+
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
25+
<createData entity="_defaultCategory" stepKey="createCategory"/>
26+
<createData entity="ApiSimpleProduct" stepKey="createProductOne">
27+
<requiredEntity createDataKey="createCategory"/>
28+
</createData>
29+
<createData entity="ApiSimpleProduct" stepKey="createProductTwo">
30+
<requiredEntity createDataKey="createCategory"/>
31+
</createData>
32+
<!-- Create new datetime product attribute -->
33+
<createData entity="DatetimeProductAttribute" stepKey="createDatetimeProduct"/>
34+
<createData entity="AddToDefaultSet" stepKey="addToDefaultSet">
35+
<requiredEntity createDataKey="createDatetimeProduct"/>
36+
</createData>
37+
</before>
38+
<after>
39+
<deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/>
40+
<deleteData createDataKey="createProductTwo" stepKey="deleteProductTwo"/>
41+
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
42+
<actionGroup ref="ClearProductsFilterActionGroup" stepKey="clearProductFilter"/>
43+
<deleteData createDataKey="createDatetimeProduct" stepKey="deleteDatetimeProduct" />
44+
<actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/>
45+
</after>
46+
<!-- Generate the datetime default value -->
47+
<generateDate date="+1 day" format="m/j/Y g:i A" stepKey="randomDatetime"/>
48+
<!-- Navigate to products list page and select created products -->
49+
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndex"/>
50+
<actionGroup ref="SearchProductGridByKeyword2ActionGroup" stepKey="searchByKeyword">
51+
<argument name="keyword" value="api-simple-product"/>
52+
</actionGroup>
53+
<actionGroup ref="SortProductsByIdDescendingActionGroup" stepKey="sortProductsByIdDescending"/>
54+
<click selector="{{AdminProductGridSection.productGridCheckboxOnRow('1')}}" stepKey="clickCheckbox1"/>
55+
<click selector="{{AdminProductGridSection.productGridCheckboxOnRow('2')}}" stepKey="clickCheckbox2"/>
56+
<!-- Mass update qty increments -->
57+
<actionGroup ref="AdminClickMassUpdateProductAttributesActionGroup" stepKey="clickMassUpdateProductAttributes"/>
58+
<actionGroup ref="AdminMassUpdateProductAttributeActionGroup" stepKey="updateAttribute">
59+
<argument name="attributeCode" value="$createDatetimeProduct.attribute_code$"/>
60+
<argument name="attributeValue" value="{$randomDatetime}"/>
61+
</actionGroup>
62+
<actionGroup ref="AdminMassUpdateProductAttributeSaveActionGroup" stepKey="saveForm"/>
63+
<!-- Start message queue for product attribute consumer -->
64+
<actionGroup ref="CliConsumerStartActionGroup" stepKey="startMessageQueue">
65+
<argument name="consumerName" value="{{AdminProductAttributeUpdateMessageConsumerData.consumerName}}"/>
66+
<argument name="maxMessages" value="{{AdminProductAttributeUpdateMessageConsumerData.messageLimit}}"/>
67+
</actionGroup>
68+
69+
<!-- Open first product for edit and assert that qty increment is updated -->
70+
<actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="goToProductEditPage">
71+
<argument name="productId" value="$createProductOne.id$"/>
72+
</actionGroup>
73+
<waitForPageLoad stepKey="waitForProductPageLoad"/>
74+
<seeInField selector="{{AdminProductFormSection.attributeRequiredInput($createDatetimeProduct.attribute_code$)}}" userInput="{$randomDatetime}" stepKey="assertQtyIncrementsValue"/>
75+
76+
<!-- Open second product for edit and assert that qty increment is updated -->
77+
<actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="goToProductEditPage2">
78+
<argument name="productId" value="$createProductTwo.id$"/>
79+
</actionGroup>
80+
<waitForPageLoad stepKey="waitForProductPageLoad2"/>
81+
<seeInField selector="{{AdminProductFormSection.attributeRequiredInput($createDatetimeProduct.attribute_code$)}}" userInput="{$randomDatetime}" stepKey="assertQtyIncrementsValue2"/>
82+
</test>
83+
</tests>

0 commit comments

Comments
 (0)