Skip to content

Commit 5ef07e5

Browse files
authored
ENGCOM-7151: Fix #6310 - Changing products 'this item has weight' using 'Update Attributes' is not possible #26075
2 parents 58c2171 + 356ba82 commit 5ef07e5

File tree

10 files changed

+752
-129
lines changed

10 files changed

+752
-129
lines changed

app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Attributes.php

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,18 @@
1313

1414
namespace Magento\Catalog\Block\Adminhtml\Product\Edit\Action\Attribute\Tab;
1515

16+
use Magento\Backend\Block\Template\Context;
17+
use Magento\Backend\Block\Widget\Tab\TabInterface;
18+
use Magento\Catalog\Block\Adminhtml\Form;
19+
use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Boolean;
20+
use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Image;
21+
use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Price;
22+
use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight;
23+
use Magento\Catalog\Helper\Product\Edit\Action\Attribute;
24+
use Magento\Catalog\Model\ProductFactory;
1625
use Magento\Framework\Data\Form\Element\AbstractElement;
26+
use Magento\Framework\Data\FormFactory;
27+
use Magento\Framework\Registry;
1728

1829
/**
1930
* Attributes tab block
@@ -23,37 +34,38 @@
2334
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2435
* @since 100.0.2
2536
*/
26-
class Attributes extends \Magento\Catalog\Block\Adminhtml\Form implements
27-
\Magento\Backend\Block\Widget\Tab\TabInterface
37+
class Attributes extends Form implements TabInterface
2838
{
2939
/**
30-
* @var \Magento\Catalog\Model\ProductFactory
40+
* @var ProductFactory
3141
*/
3242
protected $_productFactory;
3343

3444
/**
35-
* @var \Magento\Catalog\Helper\Product\Edit\Action\Attribute
45+
* @var Attribute
3646
*/
3747
protected $_attributeAction;
3848

39-
/** @var array */
49+
/**
50+
* @var array
51+
*/
4052
private $excludeFields;
4153

4254
/**
43-
* @param \Magento\Backend\Block\Template\Context $context
44-
* @param \Magento\Framework\Registry $registry
45-
* @param \Magento\Framework\Data\FormFactory $formFactory
46-
* @param \Magento\Catalog\Model\ProductFactory $productFactory
47-
* @param \Magento\Catalog\Helper\Product\Edit\Action\Attribute $attributeAction
55+
* @param Context $context
56+
* @param Registry $registry
57+
* @param FormFactory $formFactory
58+
* @param ProductFactory $productFactory
59+
* @param Attribute $attributeAction
4860
* @param array $data
4961
* @param array|null $excludeFields
5062
*/
5163
public function __construct(
52-
\Magento\Backend\Block\Template\Context $context,
53-
\Magento\Framework\Registry $registry,
54-
\Magento\Framework\Data\FormFactory $formFactory,
55-
\Magento\Catalog\Model\ProductFactory $productFactory,
56-
\Magento\Catalog\Helper\Product\Edit\Action\Attribute $attributeAction,
64+
Context $context,
65+
Registry $registry,
66+
FormFactory $formFactory,
67+
ProductFactory $productFactory,
68+
Attribute $attributeAction,
5769
array $data = [],
5870
array $excludeFields = null
5971
) {
@@ -72,7 +84,7 @@ public function __construct(
7284
*/
7385
protected function _prepareForm(): void
7486
{
75-
$this->setFormExcludedFieldList($this->getExcludedFields());
87+
$this->setFormExcludedFieldList($this->excludeFields);
7688
$this->_eventManager->dispatch(
7789
'adminhtml_catalog_product_form_prepare_excluded_field_list',
7890
['object' => $this]
@@ -110,10 +122,10 @@ public function getAttributes()
110122
protected function _getAdditionalElementTypes()
111123
{
112124
return [
113-
'price' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Price::class,
114-
'weight' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight::class,
115-
'image' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Image::class,
116-
'boolean' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Boolean::class
125+
'price' => Price::class,
126+
'weight' => Weight::class,
127+
'image' => Image::class,
128+
'boolean' => Boolean::class
117129
];
118130
}
119131

@@ -129,7 +141,7 @@ protected function _getAdditionalElementHtml($element)
129141
$nameAttributeHtml = $element->getExtType() === 'multiple' ? 'name="' . $element->getId() . '_checkbox"' : '';
130142
$elementId = $element->getId();
131143
$dataAttribute = "data-disable='{$elementId}'";
132-
$dataCheckboxName = "toggle_" . "{$elementId}";
144+
$dataCheckboxName = "toggle_{$elementId}";
133145
$checkboxLabel = __('Change');
134146
// @codingStandardsIgnoreStart
135147
$html = <<<HTML
@@ -140,14 +152,8 @@ protected function _getAdditionalElementHtml($element)
140152
</label>
141153
</span>
142154
HTML;
143-
if ($elementId === 'weight') {
144-
$html .= <<<HTML
145-
<script>require(['Magento_Catalog/js/product/weight-handler'], function (weightHandle) {
146-
weightHandle.hideWeightSwitcher();
147-
});</script>
148-
HTML;
149-
// @codingStandardsIgnoreEnd
150-
}
155+
156+
// @codingStandardsIgnoreEnd
151157
return $html;
152158
}
153159

@@ -190,14 +196,4 @@ public function isHidden()
190196
{
191197
return false;
192198
}
193-
194-
/**
195-
* Returns excluded fields
196-
*
197-
* @return array
198-
*/
199-
private function getExcludedFields(): array
200-
{
201-
return $this->excludeFields;
202-
}
203199
}

app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Weight.php

Lines changed: 112 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,64 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

7-
/**
8-
* Product form weight field helper
9-
*/
108
namespace Magento\Catalog\Block\Adminhtml\Product\Helper\Form;
119

10+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
11+
use Magento\Directory\Helper\Data;
1212
use Magento\Framework\Data\Form;
1313
use Magento\Catalog\Model\Product\Edit\WeightResolver;
14+
use Magento\Framework\Data\Form\Element\CollectionFactory;
15+
use Magento\Framework\Data\Form\Element\Factory;
16+
use Magento\Framework\Data\Form\Element\Radios;
17+
use Magento\Framework\Data\Form\Element\Text;
18+
use Magento\Framework\Escaper;
19+
use Magento\Framework\Locale\Format;
1420

15-
class Weight extends \Magento\Framework\Data\Form\Element\Text
21+
/**
22+
* Product form weight field helper
23+
*/
24+
class Weight extends Text
1625
{
1726
/**
1827
* Weight switcher radio-button element
1928
*
20-
* @var \Magento\Framework\Data\Form\Element\Checkbox
29+
* @var Radios
2130
*/
2231
protected $weightSwitcher;
2332

2433
/**
25-
* @var \Magento\Framework\Locale\Format
34+
* @var Format
2635
*/
2736
protected $localeFormat;
2837

2938
/**
30-
* @var \Magento\Directory\Helper\Data
39+
* @var Data
3140
*/
3241
protected $directoryHelper;
3342

3443
/**
35-
* @param \Magento\Framework\Data\Form\Element\Factory $factoryElement
36-
* @param \Magento\Framework\Data\Form\Element\CollectionFactory $factoryCollection
37-
* @param \Magento\Framework\Escaper $escaper
38-
* @param \Magento\Framework\Locale\Format $localeFormat
39-
* @param \Magento\Directory\Helper\Data $directoryHelper
44+
* @param Factory $factoryElement
45+
* @param CollectionFactory $factoryCollection
46+
* @param Escaper $escaper
47+
* @param Format $localeFormat
48+
* @param Data $directoryHelper
4049
* @param array $data
4150
*/
4251
public function __construct(
43-
\Magento\Framework\Data\Form\Element\Factory $factoryElement,
44-
\Magento\Framework\Data\Form\Element\CollectionFactory $factoryCollection,
45-
\Magento\Framework\Escaper $escaper,
46-
\Magento\Framework\Locale\Format $localeFormat,
47-
\Magento\Directory\Helper\Data $directoryHelper,
52+
Factory $factoryElement,
53+
CollectionFactory $factoryCollection,
54+
Escaper $escaper,
55+
Format $localeFormat,
56+
Data $directoryHelper,
4857
array $data = []
4958
) {
5059
$this->directoryHelper = $directoryHelper;
5160
$this->localeFormat = $localeFormat;
5261
$this->weightSwitcher = $factoryElement->create('radios');
5362
$this->weightSwitcher->setValue(
54-
WeightResolver::HAS_WEIGHT
63+
WeightResolver::HAS_NO_WEIGHT
5564
)->setValues(
5665
[
5766
['value' => WeightResolver::HAS_WEIGHT, 'label' => __('Yes')],
@@ -75,28 +84,44 @@ public function __construct(
7584
*/
7685
public function getElementHtml()
7786
{
78-
if (!$this->getForm()->getDataObject()->getTypeInstance()->hasWeight()) {
79-
$this->weightSwitcher->setValue(WeightResolver::HAS_NO_WEIGHT);
80-
}
8187
if ($this->getDisabled()) {
8288
$this->weightSwitcher->setDisabled($this->getDisabled());
8389
}
84-
return '<div class="admin__field-control weight-switcher">' .
85-
'<div class="admin__control-switcher" data-role="weight-switcher">' .
86-
$this->weightSwitcher->getLabelHtml() .
87-
'<div class="admin__field-control-group">' .
88-
$this->weightSwitcher->getElementHtml() .
89-
'</div>' .
90-
'</div>' .
91-
'<div class="admin__control-addon">' .
92-
parent::getElementHtml() .
93-
'<label class="admin__addon-suffix" for="' .
94-
$this->getHtmlId() .
95-
'"><span>' .
96-
$this->directoryHelper->getWeightUnit() .
97-
'</span></label>' .
98-
'</div>' .
99-
'</div>';
90+
91+
$htmlId = $this->getHtmlId();
92+
$html = '';
93+
94+
if ($beforeElementHtml = $this->getBeforeElementHtml()) {
95+
$html .= '<label class="addbefore" for="' . $htmlId . '">' . $beforeElementHtml . '</label>';
96+
}
97+
98+
$html .= '<div class="admin__control-addon">';
99+
100+
if (is_array($this->getValue())) {
101+
foreach ($this->getValue() as $value) {
102+
$html .= $this->getHtmlForInputByValue($this->_escape($value));
103+
}
104+
} else {
105+
$html .= $this->getHtmlForInputByValue($this->getEscapedValue());
106+
}
107+
108+
$html .= '<label class="admin__addon-suffix" for="' .
109+
$this->getHtmlId() .
110+
'"><span>' .
111+
$this->directoryHelper->getWeightUnit() .
112+
'</span></label></div>';
113+
114+
if ($afterElementJs = $this->getAfterElementJs()) {
115+
$html .= $afterElementJs;
116+
}
117+
118+
if ($afterElementHtml = $this->getAfterElementHtml()) {
119+
$html .= '<label class="addafter" for="' . $htmlId . '">' . $afterElementHtml . '</label>';
120+
}
121+
122+
$html .= $this->getHtmlForWeightSwitcher();
123+
124+
return $html;
100125
}
101126

102127
/**
@@ -112,8 +137,7 @@ public function setForm($form)
112137
}
113138

114139
/**
115-
* @param null|int|string $index
116-
* @return null|string
140+
* @inheritDoc
117141
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
118142
*/
119143
public function getEscapedValue($index = null)
@@ -134,4 +158,53 @@ public function getEscapedValue($index = null)
134158

135159
return $value;
136160
}
161+
162+
/**
163+
* Get input html by sting value.
164+
*
165+
* @param string|null $value
166+
*
167+
* @return string
168+
*/
169+
private function getHtmlForInputByValue($value)
170+
{
171+
return '<input id="' . $this->getHtmlId() . '" name="' . $this->getName() . '" ' . $this->_getUiId()
172+
. ' value="' . $value . '" ' . $this->serialize($this->getHtmlAttributes()) . '/>';
173+
}
174+
175+
/**
176+
* Get weight switcher html.
177+
*
178+
* @return string
179+
*/
180+
private function getHtmlForWeightSwitcher()
181+
{
182+
$html = '<div class="admin__control-addon">';
183+
$html .= '<div class="admin__field-control weight-switcher">' .
184+
'<div class="admin__control-switcher" data-role="weight-switcher">' .
185+
$this->weightSwitcher->getLabelHtml() .
186+
'<div class="admin__field-control-group">' .
187+
$this->weightSwitcher->getElementHtml() .
188+
'</div>' .
189+
'</div>';
190+
191+
$html .= '<label class="addafter">';
192+
$elementId = ProductAttributeInterface::CODE_HAS_WEIGHT;
193+
$nameAttributeHtml = 'name="' . $elementId . '_checkbox"';
194+
$dataCheckboxName = "toggle_{$elementId}";
195+
$checkboxLabel = __('Change');
196+
$html .= <<<HTML
197+
<span class="attribute-change-checkbox">
198+
<input type="checkbox" id="$dataCheckboxName" name="$dataCheckboxName" class="checkbox" $nameAttributeHtml
199+
onclick="toogleFieldEditMode(this, 'weight-switcher1'); toogleFieldEditMode(this, 'weight-switcher0');" />
200+
<label class="label" for="$dataCheckboxName">
201+
{$checkboxLabel}
202+
</label>
203+
</span>
204+
HTML;
205+
206+
$html .= '</label></div></div>';
207+
208+
return $html;
209+
}
137210
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
namespace Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute;
88

99
use Magento\AsynchronousOperations\Api\Data\OperationInterface;
10+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
1011
use Magento\Eav\Model\Config;
1112
use Magento\Framework\App\Action\HttpPostActionInterface;
1213
use Magento\Backend\App\Action;
1314
use Magento\Framework\App\ObjectManager;
1415
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
1516

1617
/**
17-
* Class Save
18+
* Class used for saving mass updated products attributes.
1819
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1920
*/
2021
class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute implements HttpPostActionInterface
@@ -146,6 +147,10 @@ private function sanitizeProductAttributes($attributesData)
146147
$dateFormat = $this->timezone->getDateFormat(\IntlDateFormatter::SHORT);
147148

148149
foreach ($attributesData as $attributeCode => $value) {
150+
if ($attributeCode === ProductAttributeInterface::CODE_HAS_WEIGHT) {
151+
continue;
152+
}
153+
149154
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
150155
if (!$attribute->getAttributeId()) {
151156
unset($attributesData[$attributeCode]);

0 commit comments

Comments
 (0)