diff --git a/app/code/Magento/Bundle/composer.json b/app/code/Magento/Bundle/composer.json
index aa2b9e12f7701..84c9a97698b71 100644
--- a/app/code/Magento/Bundle/composer.json
+++ b/app/code/Magento/Bundle/composer.json
@@ -25,7 +25,8 @@
},
"suggest": {
"magento/module-webapi": "*",
- "magento/module-bundle-sample-data": "*"
+ "magento/module-bundle-sample-data": "*",
+ "magento/module-sales-rule": "*"
},
"type": "magento2-module",
"license": [
diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml
index b7fba3937ded4..733b089dccd4b 100644
--- a/app/code/Magento/Bundle/etc/di.xml
+++ b/app/code/Magento/Bundle/etc/di.xml
@@ -207,4 +207,11 @@
+
+
+
+ - false
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckRegisterCheckoutObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckRegisterCheckoutObserverTest.php
new file mode 100644
index 0000000000000..89012ef653838
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Unit/Observer/CheckRegisterCheckoutObserverTest.php
@@ -0,0 +1,211 @@
+createMock(Onepage::class);
+ $captchaHelperMock = $this->createMock(CaptchaDataHelper::class);
+ $this->objectManager = new ObjectManager($this);
+ $this->actionFlagMock = $this->createMock(ActionFlag::class);
+ $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class);
+ $this->captchaModelMock = $this->createMock(CaptchaModel::class);
+ $this->quoteModelMock = $this->createMock(Quote::class);
+ $this->controllerMock = $this->createMock(Action::class);
+ $this->requestMock = $this->createMock(Http::class);
+ $this->responseMock = $this->createMock(HttpResponse::class);
+ $this->observer = new Observer(['controller_action' => $this->controllerMock]);
+ $this->jsonHelperMock = $this->createMock(JsonHelper::class);
+
+ $this->checkRegisterCheckoutObserver = $this->objectManager->getObject(
+ CheckRegisterCheckoutObserver::class,
+ [
+ 'helper' => $captchaHelperMock,
+ 'actionFlag' => $this->actionFlagMock,
+ 'captchaStringResolver' => $this->captchaStringResolverMock,
+ 'typeOnepage' => $onepageModelTypeMock,
+ 'jsonHelper' => $this->jsonHelperMock
+ ]
+ );
+
+ $captchaHelperMock->expects($this->once())
+ ->method('getCaptcha')
+ ->with(self::FORM_ID)
+ ->willReturn($this->captchaModelMock);
+ $onepageModelTypeMock->expects($this->once())
+ ->method('getQuote')
+ ->willReturn($this->quoteModelMock);
+ }
+
+ public function testCheckRegisterCheckoutForGuest()
+ {
+ $this->quoteModelMock->expects($this->once())
+ ->method('getCheckoutMethod')
+ ->willReturn(Onepage::METHOD_GUEST);
+ $this->captchaModelMock->expects($this->never())
+ ->method('isRequired');
+
+ $this->checkRegisterCheckoutObserver->execute($this->observer);
+ }
+
+ public function testCheckRegisterCheckoutWithNoCaptchaRequired()
+ {
+ $this->quoteModelMock->expects($this->once())
+ ->method('getCheckoutMethod')
+ ->willReturn(Onepage::METHOD_REGISTER);
+ $this->captchaModelMock->expects($this->once())
+ ->method('isRequired')
+ ->willReturn(false);
+ $this->captchaModelMock->expects($this->never())
+ ->method('isCorrect');
+
+ $this->checkRegisterCheckoutObserver->execute($this->observer);
+ }
+
+ public function testCheckRegisterCheckoutWithIncorrectCaptcha()
+ {
+ $captchaValue = 'some_word';
+ $encodedJsonValue = '{}';
+
+ $this->quoteModelMock->expects($this->once())
+ ->method('getCheckoutMethod')
+ ->willReturn(Onepage::METHOD_REGISTER);
+ $this->captchaModelMock->expects($this->once())
+ ->method('isRequired')
+ ->willReturn(true);
+ $this->controllerMock->expects($this->once())
+ ->method('getRequest')
+ ->willReturn($this->requestMock);
+ $this->controllerMock->expects($this->once())
+ ->method('getResponse')
+ ->willReturn($this->responseMock);
+ $this->controllerMock->expects($this->once())
+ ->method('getResponse')
+ ->willReturn($this->responseMock);
+ $this->captchaStringResolverMock->expects($this->once())
+ ->method('resolve')
+ ->with($this->requestMock, self::FORM_ID)
+ ->willReturn($captchaValue);
+ $this->captchaModelMock->expects($this->once())
+ ->method('isCorrect')
+ ->with($captchaValue)
+ ->willReturn(false);
+ $this->actionFlagMock->expects($this->once())
+ ->method('set')
+ ->with('', Action::FLAG_NO_DISPATCH, true);
+ $this->jsonHelperMock->expects($this->once())
+ ->method('jsonEncode')
+ ->willReturn($encodedJsonValue);
+ $this->responseMock->expects($this->once())
+ ->method('representJson')
+ ->with($encodedJsonValue);
+
+ $this->checkRegisterCheckoutObserver->execute($this->observer);
+ }
+
+ public function testCheckRegisterCheckoutWithCorrectCaptcha()
+ {
+ $this->quoteModelMock->expects($this->once())
+ ->method('getCheckoutMethod')
+ ->willReturn(Onepage::METHOD_REGISTER);
+ $this->captchaModelMock->expects($this->once())
+ ->method('isRequired')
+ ->willReturn(true);
+ $this->controllerMock->expects($this->once())
+ ->method('getRequest')
+ ->willReturn($this->requestMock);
+ $this->captchaStringResolverMock->expects($this->once())
+ ->method('resolve')
+ ->with($this->requestMock, self::FORM_ID)
+ ->willReturn('some_word');
+ $this->captchaModelMock->expects($this->once())
+ ->method('isCorrect')
+ ->with('some_word')
+ ->willReturn(true);
+ $this->actionFlagMock->expects($this->never())
+ ->method('set');
+
+ $this->checkRegisterCheckoutObserver->execute($this->observer);
+ }
+}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
index 13c4353e65204..1e0cb9f197a51 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
@@ -3,8 +3,12 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Controller\Adminhtml;
+use Magento\Store\Model\Store;
+
/**
* Catalog category controller
*/
@@ -44,7 +48,7 @@ public function __construct(
protected function _initCategory($getRootInstead = false)
{
$categoryId = $this->resolveCategoryId();
- $storeId = (int)$this->getRequest()->getParam('store');
+ $storeId = $this->resolveStoreId();
$category = $this->_objectManager->create(\Magento\Catalog\Model\Category::class);
$category->setStoreId($storeId);
@@ -70,7 +74,7 @@ protected function _initCategory($getRootInstead = false)
$this->_objectManager->get(\Magento\Framework\Registry::class)->register('category', $category);
$this->_objectManager->get(\Magento\Framework\Registry::class)->register('current_category', $category);
$this->_objectManager->get(\Magento\Cms\Model\Wysiwyg\Config::class)
- ->setStoreId($this->getRequest()->getParam('store'));
+ ->setStoreId($storeId);
return $category;
}
@@ -79,13 +83,28 @@ protected function _initCategory($getRootInstead = false)
*
* @return int
*/
- private function resolveCategoryId()
+ private function resolveCategoryId() : int
{
$categoryId = (int)$this->getRequest()->getParam('id', false);
return $categoryId ?: (int)$this->getRequest()->getParam('entity_id', false);
}
+ /**
+ * Resolve store id
+ *
+ * Tries to take store id from store HTTP parameter
+ * @see Store
+ *
+ * @return int
+ */
+ private function resolveStoreId() : int
+ {
+ $storeId = (int)$this->getRequest()->getParam('store', false);
+
+ return $storeId ?: (int)$this->getRequest()->getParam('store_id', Store::DEFAULT_STORE_ID);
+ }
+
/**
* Build response for ajax request
*
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
index e054a9d49b437..817de6828e48d 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
@@ -69,6 +69,7 @@ class Save extends Attribute
* @var LayoutFactory
*/
private $layoutFactory;
+
/**
* @var Presentation
*/
@@ -124,6 +125,7 @@ public function execute()
{
$data = $this->getRequest()->getPostValue();
if ($data) {
+ $this->preprocessOptionsData($data);
$setId = $this->getRequest()->getParam('set');
$attributeSet = null;
@@ -313,6 +315,28 @@ public function execute()
return $this->returnResult('catalog/*/', [], ['error' => true]);
}
+ /**
+ * Extract options data from serialized options field and append to data array.
+ *
+ * This logic is required to overcome max_input_vars php limit
+ * that may vary and/or be inaccessible to change on different instances.
+ *
+ * @param array $data
+ * @return void
+ */
+ private function preprocessOptionsData(&$data)
+ {
+ if (isset($data['serialized_options'])) {
+ $serializedOptions = json_decode($data['serialized_options'], JSON_OBJECT_AS_ARRAY);
+ foreach ($serializedOptions as $serializedOption) {
+ $option = [];
+ parse_str($serializedOption, $option);
+ $data = array_replace_recursive($data, $option);
+ }
+ }
+ unset($data['serialized_options']);
+ }
+
/**
* @param string $path
* @param array $params
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php
index af10eeea42fd3..473f1aea33618 100644
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php
@@ -63,7 +63,8 @@ protected function setUp()
'getAttributes',
'getStore',
'getAttributeDefaultValue',
- 'getExistsStoreValueFlag'
+ 'getExistsStoreValueFlag',
+ 'isLockedAttribute'
])->getMockForAbstractClass();
$this->storeMock = $this->getMockBuilder(StoreInterface::class)
->setMethods(['load', 'getId', 'getConfig'])
@@ -81,9 +82,6 @@ protected function setUp()
$this->arrayManagerMock->expects($this->any())
->method('set')
->willReturnArgument(1);
- $this->arrayManagerMock->expects($this->any())
- ->method('merge')
- ->willReturnArgument(1);
$this->arrayManagerMock->expects($this->any())
->method('remove')
->willReturnArgument(1);
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AttributeSetTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AttributeSetTest.php
index c22dde0b456ac..5fc6231b03735 100644
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AttributeSetTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AttributeSetTest.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Catalog\Test\Unit\Ui\DataProvider\Product\Form\Modifier;
+use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AttributeSet;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection;
@@ -84,7 +85,30 @@ protected function createModel()
public function testModifyMeta()
{
- $this->assertNotEmpty($this->getModel()->modifyMeta(['test_group' => []]));
+ $modifyMeta = $this->getModel()->modifyMeta(['test_group' => []]);
+ $this->assertNotEmpty($modifyMeta);
+ }
+
+ /**
+ * @param bool $locked
+ * @dataProvider modifyMetaLockedDataProvider
+ */
+ public function testModifyMetaLocked($locked)
+ {
+ $this->productMock->expects($this->any())
+ ->method('isLockedAttribute')
+ ->willReturn($locked);
+ $modifyMeta = $this->getModel()->modifyMeta([AbstractModifier::DEFAULT_GENERAL_PANEL => []]);
+ $children = $modifyMeta[AbstractModifier::DEFAULT_GENERAL_PANEL]['children'];
+ $this->assertEquals(
+ $locked,
+ $children['attribute_set_id']['arguments']['data']['config']['disabled']
+ );
+ }
+
+ public function modifyMetaLockedDataProvider()
+ {
+ return [[true], [false]];
}
public function testModifyMetaToBeEmpty()
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
index 4daff7e7930e3..5f5913c20209a 100644
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
@@ -114,6 +114,44 @@ public function testModifyMeta()
$this->assertArrayHasKey($groupCode, $this->getModel()->modifyMeta($meta));
}
+ /**
+ * @param bool $locked
+ * @dataProvider modifyMetaLockedDataProvider
+ */
+ public function testModifyMetaLocked($locked)
+ {
+ $groupCode = 'test_group_code';
+ $meta = [
+ $groupCode => [
+ 'children' => [
+ 'category_ids' => [
+ 'sortOrder' => 10,
+ ],
+ ],
+ ],
+ ];
+
+ $this->arrayManagerMock->expects($this->any())
+ ->method('findPath')
+ ->willReturn('path');
+
+ $this->productMock->expects($this->any())
+ ->method('isLockedAttribute')
+ ->willReturn($locked);
+
+ $this->arrayManagerMock->expects($this->any())
+ ->method('merge')
+ ->willReturnArgument(2);
+
+ $modifyMeta = $this->createModel()->modifyMeta($meta);
+ $this->assertEquals($locked, $modifyMeta['arguments']['data']['config']['disabled']);
+ }
+
+ public function modifyMetaLockedDataProvider()
+ {
+ return [[true], [false]];
+ }
+
public function testModifyMetaWithCaching()
{
$this->arrayManagerMock->expects($this->exactly(2))
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php
index 0426e389d9aeb..22bb712d42f0f 100755
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php
@@ -462,7 +462,7 @@ public function testModifyData()
* @param bool $productRequired
* @param string|null $attrValue
* @param array $expected
- * @return void
+ * @param bool $locked
* @covers \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav::isProductExists
* @covers \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav::setupAttributeMeta
* @dataProvider setupAttributeMetaDataProvider
@@ -471,7 +471,8 @@ public function testSetupAttributeMetaDefaultAttribute(
$productId,
bool $productRequired,
$attrValue,
- array $expected
+ array $expected,
+ $locked = false
) : void {
$configPath = 'arguments/data/config';
$groupCode = 'product-details';
@@ -492,6 +493,7 @@ public function testSetupAttributeMetaDefaultAttribute(
];
$this->productMock->method('getId')->willReturn($productId);
+ $this->productMock->expects($this->any())->method('isLockedAttribute')->willReturn($locked);
$this->productAttributeMock->method('getIsRequired')->willReturn($productRequired);
$this->productAttributeMock->method('getDefaultValue')->willReturn('required_value');
$this->productAttributeMock->method('getAttributeCode')->willReturn('code');
@@ -520,14 +522,14 @@ public function testSetupAttributeMetaDefaultAttribute(
)
->willReturn($expected);
- $this->arrayManagerMock->expects($this->once())
+ $this->arrayManagerMock->expects($this->any())
->method('merge')
->with(
$this->anything(),
$this->anything(),
$this->callback(
function ($value) use ($attributeOptionsExpected) {
- return $value['options'] === $attributeOptionsExpected;
+ return isset($value['options']) ? $value['options'] === $attributeOptionsExpected : true;
}
)
)
@@ -544,6 +546,7 @@ function ($value) use ($attributeOptionsExpected) {
/**
* @return array
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function setupAttributeMetaDataProvider()
{
@@ -567,6 +570,26 @@ public function setupAttributeMetaDataProvider()
'sortOrder' => 0,
],
],
+ 'default_null_prod_not_new_locked_and_required' => [
+ 'productId' => 1,
+ 'productRequired' => true,
+ 'attrValue' => 'val',
+ 'expected' => [
+ 'dataType' => null,
+ 'formElement' => null,
+ 'visible' => null,
+ 'required' => true,
+ 'notice' => null,
+ 'default' => null,
+ 'label' => new Phrase(null),
+ 'code' => 'code',
+ 'source' => 'product-details',
+ 'scopeLabel' => '',
+ 'globalScope' => false,
+ 'sortOrder' => 0,
+ ],
+ 'locked' => true,
+ ],
'default_null_prod_not_new_and_not_required' => [
'productId' => 1,
'productRequired' => false,
@@ -605,6 +628,26 @@ public function setupAttributeMetaDataProvider()
'sortOrder' => 0,
],
],
+ 'default_null_prod_new_locked_and_not_required' => [
+ 'productId' => null,
+ 'productRequired' => false,
+ 'attrValue' => null,
+ 'expected' => [
+ 'dataType' => null,
+ 'formElement' => null,
+ 'visible' => null,
+ 'required' => false,
+ 'notice' => null,
+ 'default' => 'required_value',
+ 'label' => new Phrase(null),
+ 'code' => 'code',
+ 'source' => 'product-details',
+ 'scopeLabel' => '',
+ 'globalScope' => false,
+ 'sortOrder' => 0,
+ ],
+ 'locked' => true,
+ ],
'default_null_prod_new_and_required' => [
'productId' => null,
'productRequired' => false,
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GeneralTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GeneralTest.php
index 78502ae297b52..a9d717db7b7f9 100644
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GeneralTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GeneralTest.php
@@ -60,6 +60,9 @@ protected function createModel()
public function testModifyMeta()
{
+ $this->arrayManagerMock->expects($this->any())
+ ->method('merge')
+ ->willReturnArgument(2);
$this->assertNotEmpty($this->getModel()->modifyMeta([
'first_panel_code' => [
'arguments' => [
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/ScheduleDesignUpdateTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/ScheduleDesignUpdateTest.php
index d4d4136bf4157..783c6247b9df3 100644
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/ScheduleDesignUpdateTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/ScheduleDesignUpdateTest.php
@@ -24,6 +24,9 @@ protected function createModel()
public function testModifyMeta()
{
+ $this->arrayManagerMock->expects($this->any())
+ ->method('merge')
+ ->willReturnArgument(1);
$this->assertSame([], $this->getModel()->modifyMeta([]));
}
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php
index 997b66861c21b..c3096770729a6 100644
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php
@@ -76,7 +76,10 @@ class WebsitesTest extends AbstractModifierTest
protected function setUp()
{
- $this->objectManager = new ObjectManager($this);
+ parent::setUp();
+ $this->productMock->expects($this->any())
+ ->method('getId')
+ ->willReturn(self::PRODUCT_ID);
$this->assignedWebsites = [self::SECOND_WEBSITE_ID];
$this->websiteMock = $this->getMockBuilder(\Magento\Store\Model\Website::class)
->setMethods(['getId', 'getName'])
@@ -101,15 +104,9 @@ protected function setUp()
$this->storeRepositoryMock = $this->getMockBuilder(\Magento\Store\Api\StoreRepositoryInterface::class)
->setMethods(['getList'])
->getMockForAbstractClass();
- $this->locatorMock = $this->getMockBuilder(\Magento\Catalog\Model\Locator\LocatorInterface::class)
- ->setMethods(['getProduct', 'getWebsiteIds'])
- ->getMockForAbstractClass();
$this->productMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class)
->setMethods(['getId'])
->getMockForAbstractClass();
- $this->locatorMock->expects($this->any())
- ->method('getProduct')
- ->willReturn($this->productMock);
$this->locatorMock->expects($this->any())
->method('getWebsiteIds')
->willReturn($this->assignedWebsites);
@@ -148,9 +145,6 @@ protected function setUp()
$this->storeRepositoryMock->expects($this->any())
->method('getList')
->willReturn([$this->storeViewMock]);
- $this->productMock->expects($this->any())
- ->method('getId')
- ->willReturn(self::PRODUCT_ID);
$this->secondWebsiteMock->expects($this->any())
->method('getId')
->willReturn($this->assignedWebsites[0]);
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php
index 63b7f5faa6562..336aeffa10584 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php
@@ -432,7 +432,8 @@ private function getTierPriceStructure($tierPricePath)
'dndConfig' => [
'enabled' => false,
],
- 'disabled' => false,
+ 'disabled' =>
+ $this->arrayManager->get($tierPricePath . '/arguments/data/config/disabled', $this->meta),
'required' => false,
'sortOrder' =>
$this->arrayManager->get($tierPricePath . '/arguments/data/config/sortOrder', $this->meta),
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AttributeSet.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AttributeSet.php
index a1aacc91f2e47..0733d21bf47d7 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AttributeSet.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AttributeSet.php
@@ -108,6 +108,7 @@ public function modifyMeta(array $meta)
self::ATTRIBUTE_SET_FIELD_ORDER
),
'multiple' => false,
+ 'disabled' => $this->locator->getProduct()->isLockedAttribute('attribute_set_id'),
];
}
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
index 7456c1bfef91f..ed737df708ab8 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
@@ -228,6 +228,7 @@ protected function customizeCategoriesField(array $meta)
'componentType' => 'container',
'component' => 'Magento_Ui/js/form/components/group',
'scopeLabel' => __('[GLOBAL]'),
+ 'disabled' => $this->locator->getProduct()->isLockedAttribute($fieldCode),
],
],
],
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
index 0e6f17d761bc3..7cd81419c0347 100755
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
@@ -41,6 +41,7 @@
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyFields)
+ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
* @since 101.0.0
*/
class Eav extends AbstractModifier
@@ -593,6 +594,7 @@ private function isProductExists()
public function setupAttributeMeta(ProductAttributeInterface $attribute, $groupCode, $sortOrder)
{
$configPath = ltrim(static::META_CONFIG_PATH, ArrayManager::DEFAULT_PATH_DELIMITER);
+ $attributeCode = $attribute->getAttributeCode();
$meta = $this->arrayManager->set($configPath, [], [
'dataType' => $attribute->getFrontendInput(),
'formElement' => $this->getFormElementsMapValue($attribute->getFrontendInput()),
@@ -601,7 +603,7 @@ public function setupAttributeMeta(ProductAttributeInterface $attribute, $groupC
'notice' => $attribute->getNote() === null ? null : __($attribute->getNote()),
'default' => (!$this->isProductExists()) ? $this->getAttributeDefaultValue($attribute) : null,
'label' => __($attribute->getDefaultFrontendLabel()),
- 'code' => $attribute->getAttributeCode(),
+ 'code' => $attributeCode,
'source' => $groupCode,
'scopeLabel' => $this->getScopeLabel($attribute),
'globalScope' => $this->isScopeGlobal($attribute),
@@ -631,7 +633,9 @@ public function setupAttributeMeta(ProductAttributeInterface $attribute, $groupC
]);
}
- if (in_array($attribute->getAttributeCode(), $this->attributesToDisable)) {
+ $product = $this->locator->getProduct();
+ if (in_array($attributeCode, $this->attributesToDisable)
+ || $product->isLockedAttribute($attributeCode)) {
$meta = $this->arrayManager->merge($configPath, $meta, [
'disabled' => true,
]);
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php
index 279b905577689..98de8ea347671 100755
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php
@@ -203,7 +203,7 @@ protected function customizeStatusField(array $meta)
protected function customizeWeightField(array $meta)
{
$weightPath = $this->arrayManager->findPath(ProductAttributeInterface::CODE_WEIGHT, $meta, null, 'children');
-
+ $disabled = $this->arrayManager->get($weightPath . '/arguments/data/config/disabled', $meta);
if ($weightPath) {
$meta = $this->arrayManager->merge(
$weightPath . static::META_CONFIG_PATH,
@@ -215,7 +215,7 @@ protected function customizeWeightField(array $meta)
],
'additionalClasses' => 'admin__field-small',
'addafter' => $this->locator->getStore()->getConfig('general/locale/weight_unit'),
- 'imports' => [
+ 'imports' => $disabled ? [] : [
'disabled' => '!${$.provider}:' . self::DATA_SCOPE_PRODUCT
. '.product_has_weight:value'
]
@@ -255,6 +255,7 @@ protected function customizeWeightField(array $meta)
],
],
'value' => (int)$this->locator->getProduct()->getTypeInstance()->hasWeight(),
+ 'disabled' => $disabled,
]
);
}
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php
index 298da3d5cd6f2..bab36ce5fc4d8 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php
@@ -135,7 +135,6 @@ public function modifyMeta(array $meta)
'collapsible' => true,
'componentType' => Form\Fieldset::NAME,
'dataScope' => self::DATA_SCOPE_PRODUCT,
- 'disabled' => false,
'sortOrder' => $this->getNextGroupSortOrder(
$meta,
'search-engine-optimization',
@@ -196,6 +195,7 @@ protected function getFieldsForFieldset()
'false' => '0',
],
'value' => $isChecked ? (string)$website['id'] : '0',
+ 'disabled' => $this->locator->getProduct()->isLockedAttribute('website_ids'),
],
],
],
diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js
index 787516a9abf29..6ea005915763c 100644
--- a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js
+++ b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js
@@ -13,12 +13,16 @@ define([
'jquery/ui',
'prototype',
'form',
- 'validation'
+ 'validation',
+ 'mage/translate'
], function (jQuery, mageTemplate, rg) {
'use strict';
return function (config) {
- var attributeOption = {
+ var optionPanel = jQuery('#manage-options-panel'),
+ optionsValues = [],
+ editForm = jQuery('#edit_form'),
+ attributeOption = {
table: $('attribute-options-table'),
itemCount: 0,
totalItems: 0,
@@ -150,7 +154,7 @@ define([
attributeOption.remove(event);
});
- jQuery('#manage-options-panel').on('render', function () {
+ optionPanel.on('render', function () {
attributeOption.ignoreValidate();
if (attributeOption.rendered) {
@@ -176,7 +180,31 @@ define([
});
});
}
+ editForm.on('submit', function () {
+ optionPanel.find('input')
+ .each(function () {
+ if (this.disabled) {
+ return;
+ }
+ if (this.type === 'checkbox' || this.type === 'radio') {
+ if (this.checked) {
+ optionsValues.push(this.name + '=' + jQuery(this).val());
+ }
+ } else {
+ optionsValues.push(this.name + '=' + jQuery(this).val());
+ }
+ });
+ jQuery('')
+ .attr({
+ type: 'hidden',
+ name: 'serialized_options'
+ })
+ .val(JSON.stringify(optionsValues))
+ .prependTo(editForm);
+ optionPanel.find('table')
+ .replaceWith(jQuery('
').text(jQuery.mage.__('Sending attribute values as package.')));
+ });
window.attributeOption = attributeOption;
window.optionDefaultInputType = attributeOption.getOptionInputType();
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/breadcrumbs.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/breadcrumbs.phtml
index 528b2b5c59f23..063f8857329e5 100644
--- a/app/code/Magento/Catalog/view/frontend/templates/product/breadcrumbs.phtml
+++ b/app/code/Magento/Catalog/view/frontend/templates/product/breadcrumbs.phtml
@@ -11,7 +11,7 @@ $viewModel = $block->getData('viewModel');
"breadcrumbs": {
"categoryUrlSuffix": "= $block->escapeHtml($viewModel->getCategoryUrlSuffix()); ?>",
"useCategoryPathInUrl": = (int)$viewModel->isCategoryUsedInProductUrl(); ?>,
- "product": "= $block->escapeHtml($block->escapeJsQuote($viewModel->getProductName(), '"')); ?>"
+ "product": "= $block->escapeHtml($block->escapeJs($viewModel->getProductName())); ?>"
}
}'>
diff --git a/app/code/Magento/CatalogInventory/Api/Data/StockStatusInterface.php b/app/code/Magento/CatalogInventory/Api/Data/StockStatusInterface.php
index 83defa64df250..c9ae6a96a3671 100644
--- a/app/code/Magento/CatalogInventory/Api/Data/StockStatusInterface.php
+++ b/app/code/Magento/CatalogInventory/Api/Data/StockStatusInterface.php
@@ -14,6 +14,14 @@
*/
interface StockStatusInterface extends ExtensibleDataInterface
{
+ /**#@+
+ * Stock Status values.
+ */
+ const STATUS_OUT_OF_STOCK = 0;
+
+ const STATUS_IN_STOCK = 1;
+ /**#@-*/
+
/**#@+
* Stock status object data keys
*/
diff --git a/app/code/Magento/CatalogInventory/Model/Stock/Status.php b/app/code/Magento/CatalogInventory/Model/Stock/Status.php
index 9a56c8e8804ec..899056d8f0835 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock/Status.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock/Status.php
@@ -17,14 +17,6 @@
*/
class Status extends AbstractExtensibleModel implements StockStatusInterface
{
- /**#@+
- * Stock Status values
- */
- const STATUS_OUT_OF_STOCK = 0;
-
- const STATUS_IN_STOCK = 1;
- /**#@-*/
-
/**#@+
* Field name
*/
diff --git a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php
index d15f17530ffbc..7386f133b569a 100644
--- a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php
+++ b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php
@@ -223,6 +223,7 @@ private function prepareMeta()
$this->arrayManager->slicePath($pathField, 0, -2) . '/arguments/data/config/sortOrder',
$this->meta
) - 1,
+ 'disabled' => $this->locator->getProduct()->isLockedAttribute($fieldCode),
];
$qty['arguments']['data']['config'] = [
'component' => 'Magento_CatalogInventory/js/components/qty-validator-changer',
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CustomOptionsTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CustomOptionsTest.php
index e2e9fe9b2b1f9..659f7346faba4 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CustomOptionsTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CustomOptionsTest.php
@@ -10,6 +10,14 @@
class CustomOptionsTest extends AbstractModifierTest
{
+ protected function setUp()
+ {
+ parent::setUp();
+ $this->arrayManagerMock->expects($this->any())
+ ->method('merge')
+ ->willReturnArgument(1);
+ }
+
/**
* {@inheritdoc}
*/
diff --git a/app/code/Magento/Customer/view/frontend/templates/form/login.phtml b/app/code/Magento/Customer/view/frontend/templates/form/login.phtml
index 16206525aa53b..77e250c5de923 100644
--- a/app/code/Magento/Customer/view/frontend/templates/form/login.phtml
+++ b/app/code/Magento/Customer/view/frontend/templates/form/login.phtml
@@ -42,3 +42,13 @@
+
+
diff --git a/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml b/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
index 73e9c4fa34bb3..223e43c9bb897 100644
--- a/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
+++ b/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml
@@ -28,9 +28,7 @@ $suffix = $block->showSuffix();
?>
getNoWrap()): ?>
-
+