@@ -22,13 +24,22 @@
= $block->getChildHtml('form_additional_info') ?>
@@ -41,3 +52,12 @@
+
diff --git a/app/code/Magento/Customer/view/frontend/templates/form/register.phtml b/app/code/Magento/Customer/view/frontend/templates/form/register.phtml
index f7d10f6df1728..e84861b9b5cf6 100644
--- a/app/code/Magento/Customer/view/frontend/templates/form/register.phtml
+++ b/app/code/Magento/Customer/view/frontend/templates/form/register.phtml
@@ -301,13 +301,6 @@ require([
ignore: ignore ? ':hidden:not(' + ignore + ')' : ':hidden'
}).find('input:text').attr('autocomplete', 'off');
- dataForm.submit(function () {
- $(this).find(':submit').attr('disabled', 'disabled');
- });
- dataForm.bind("invalid-form.validate", function () {
- $(this).find(':submit').prop('disabled', false);
- });
-
});
getShowAddressFields()): ?>
@@ -337,6 +330,11 @@ require([
"passwordStrengthIndicator": {
"formSelector": "form.form-create-account"
}
+ },
+ "*": {
+ "Magento_Customer/js/block-submit-on-send": {
+ "formId": "form-validate"
+ }
}
}
diff --git a/app/code/Magento/Customer/view/frontend/web/js/block-submit-on-send.js b/app/code/Magento/Customer/view/frontend/web/js/block-submit-on-send.js
new file mode 100644
index 0000000000000..b941ec7a254d8
--- /dev/null
+++ b/app/code/Magento/Customer/view/frontend/web/js/block-submit-on-send.js
@@ -0,0 +1,22 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+ 'jquery',
+ 'mage/mage'
+], function ($) {
+ 'use strict';
+
+ return function (config) {
+ var dataForm = $('#' + config.formId);
+
+ dataForm.submit(function () {
+ $(this).find(':submit').attr('disabled', 'disabled');
+ });
+ dataForm.bind('invalid-form.validate', function () {
+ $(this).find(':submit').prop('disabled', false);
+ });
+ };
+});
diff --git a/app/code/Magento/GoogleOptimizer/Observer/AbstractSave.php b/app/code/Magento/GoogleOptimizer/Observer/AbstractSave.php
index 135c8c92c6aa9..975788abe52e4 100644
--- a/app/code/Magento/GoogleOptimizer/Observer/AbstractSave.php
+++ b/app/code/Magento/GoogleOptimizer/Observer/AbstractSave.php
@@ -5,12 +5,16 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\GoogleOptimizer\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
/**
+ * Abstract entity for saving codes
+ *
* @api
* @since 100.0.2
*/
@@ -96,7 +100,9 @@ protected function _processCode()
$this->_initRequestParams();
if ($this->_isNewCode()) {
- $this->_saveCode();
+ if (!$this->_isEmptyCode()) {
+ $this->_saveCode();
+ }
} else {
$this->_loadCode();
if ($this->_isEmptyCode()) {
@@ -185,6 +191,8 @@ protected function _deleteCode()
}
/**
+ * Check data availability
+ *
* @return bool
*/
private function isDataAvailable()
@@ -194,6 +202,8 @@ private function isDataAvailable()
}
/**
+ * Get request data
+ *
* @return mixed
*/
private function getRequestData()
diff --git a/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Product/SaveGoogleExperimentScriptObserverTest.php b/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Product/SaveGoogleExperimentScriptObserverTest.php
index 8a5c247369657..c6d02957c4be9 100644
--- a/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Product/SaveGoogleExperimentScriptObserverTest.php
+++ b/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Product/SaveGoogleExperimentScriptObserverTest.php
@@ -127,6 +127,39 @@ public function testCreatingCodeIfRequestIsValid()
$this->_modelObserver->execute($this->_eventObserverMock);
}
+ /**
+ * Test that code is not saving when request is empty
+ *
+ * @return void
+ */
+ public function testCreatingCodeIfRequestIsEmpty(): void
+ {
+ $this->_helperMock->expects(
+ $this->once()
+ )->method(
+ 'isGoogleExperimentActive'
+ )->with(
+ $this->_storeId
+ )->willReturn(
+ true
+ );
+
+ $this->_requestMock->expects(
+ $this->exactly(3)
+ )->method(
+ 'getParam'
+ )->with(
+ 'google_experiment'
+ )->willReturn(
+ ['code_id' => '', 'experiment_script' => '']
+ );
+
+ $this->_codeMock->expects($this->never())->method('addData');
+ $this->_codeMock->expects($this->never())->method('save');
+
+ $this->_modelObserver->execute($this->_eventObserverMock);
+ }
+
/**
* @param array $params
* @dataProvider dataProviderWrongRequestForCreating
diff --git a/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml b/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml
index 429482e5795bf..768c97ef316f7 100644
--- a/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml
+++ b/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml
@@ -40,3 +40,12 @@
+
diff --git a/app/code/Magento/Quote/Model/Quote/Item/Processor.php b/app/code/Magento/Quote/Model/Quote/Item/Processor.php
index ef4b853862681..c6bef1cc80bfb 100644
--- a/app/code/Magento/Quote/Model/Quote/Item/Processor.php
+++ b/app/code/Magento/Quote/Model/Quote/Item/Processor.php
@@ -97,7 +97,9 @@ public function prepare(Item $item, DataObject $request, Product $candidate): vo
$item->addQty($candidate->getCartQty());
$customPrice = $request->getCustomPrice();
- $item->setPrice($candidate->getFinalPrice());
+ if (!$item->getParentItem() || $item->getParentItem()->isChildrenCalculated()) {
+ $item->setPrice($candidate->getFinalPrice());
+ }
if (!empty($customPrice)) {
$item->setCustomPrice($customPrice);
$item->setOriginalCustomPrice($customPrice);
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/ProcessorTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/ProcessorTest.php
index cbcb7dd0adc3c..3025a72410671 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/ProcessorTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/ProcessorTest.php
@@ -77,7 +77,16 @@ protected function setUp(): void
$this->itemMock = $this->getMockBuilder(Item::class)
->addMethods(['setOriginalCustomPrice'])
- ->onlyMethods(['getId', 'setOptions', 'setProduct', 'addQty', 'setCustomPrice', 'setData', 'setPrice'])
+ ->onlyMethods([
+ 'getId',
+ 'setOptions',
+ 'setProduct',
+ 'addQty',
+ 'setCustomPrice',
+ 'setData',
+ 'setPrice',
+ 'getParentItem'
+ ])
->disableOriginalConstructor()
->getMock();
$this->quoteItemFactoryMock->expects($this->any())
@@ -438,4 +447,41 @@ public function testPrepareWithResetCountAndNotStickAndSameItemId()
$this->processor->prepare($this->itemMock, $this->objectMock, $this->productMock);
}
+
+ /**
+ * @param bool $isChildrenCalculated
+ * @dataProvider prepareChildProductDataProvider
+ */
+ public function testPrepareChildProduct(bool $isChildrenCalculated): void
+ {
+ $finalPrice = 10;
+ $this->objectMock->method('getResetCount')
+ ->willReturn(false);
+ $this->productMock->method('getFinalPrice')
+ ->willReturn($finalPrice);
+ $this->itemMock->expects($isChildrenCalculated ? $this->once() : $this->never())
+ ->method('setPrice')
+ ->with($finalPrice)
+ ->willReturnSelf();
+ $parentItem = $this->createConfiguredMock(
+ \Magento\Quote\Model\Quote\Item::class,
+ [
+ 'isChildrenCalculated' => $isChildrenCalculated
+ ]
+ );
+ $this->itemMock->method('getParentItem')
+ ->willReturn($parentItem);
+ $this->processor->prepare($this->itemMock, $this->objectMock, $this->productMock);
+ }
+
+ /**
+ * @return array
+ */
+ public function prepareChildProductDataProvider(): array
+ {
+ return [
+ [false],
+ [true]
+ ];
+ }
}
diff --git a/app/code/Magento/SalesRule/view/frontend/requirejs-config.js b/app/code/Magento/SalesRule/view/frontend/requirejs-config.js
index 13b701c6fe65a..21f49fb3080fc 100644
--- a/app/code/Magento/SalesRule/view/frontend/requirejs-config.js
+++ b/app/code/Magento/SalesRule/view/frontend/requirejs-config.js
@@ -8,6 +8,9 @@ var config = {
mixins: {
'Magento_Checkout/js/action/select-payment-method': {
'Magento_SalesRule/js/action/select-payment-method-mixin': true
+ },
+ 'Magento_Checkout/js/model/shipping-save-processor': {
+ 'Magento_SalesRule/js/model/shipping-save-processor-mixin': true
}
}
}
diff --git a/app/code/Magento/SalesRule/view/frontend/web/js/model/shipping-save-processor-mixin.js b/app/code/Magento/SalesRule/view/frontend/web/js/model/shipping-save-processor-mixin.js
new file mode 100644
index 0000000000000..193acb8eed2f4
--- /dev/null
+++ b/app/code/Magento/SalesRule/view/frontend/web/js/model/shipping-save-processor-mixin.js
@@ -0,0 +1,34 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+define([
+ 'mage/utils/wrapper',
+ 'Magento_Checkout/js/model/quote',
+ 'Magento_SalesRule/js/model/coupon'
+], function (wrapper, quote, coupon) {
+ 'use strict';
+
+ return function (shippingSaveProcessor) {
+ shippingSaveProcessor.saveShippingInformation = wrapper.wrapSuper(
+ shippingSaveProcessor.saveShippingInformation,
+ function (type) {
+ var updateCouponCallback;
+
+ /**
+ * Update coupon form
+ */
+ updateCouponCallback = function () {
+ if (quote.totals() && !quote.totals()['coupon_code']) {
+ coupon.setCouponCode('');
+ coupon.setIsApplied(false);
+ }
+ };
+
+ return this._super(type).done(updateCouponCallback);
+ }
+ );
+
+ return shippingSaveProcessor;
+ };
+});
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Price/SpecialPriceStorageTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Price/SpecialPriceStorageTest.php
new file mode 100644
index 0000000000000..0d8b0a825d24c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Price/SpecialPriceStorageTest.php
@@ -0,0 +1,69 @@
+model = $objectManager->get(SpecialPriceStorage::class);
+ $this->specialPriceFactory = $objectManager->get(SpecialPriceInterfaceFactory::class);
+ }
+
+ /**
+ * Test that price update validation works correctly
+ *
+ * @magentoDataFixture Magento/Catalog/_files/category_product.php
+ */
+ public function testUpdateValidationResult()
+ {
+ $date = new \Datetime('+2 days');
+ $date->setTime(0, 0);
+ /** @var SpecialPriceInterface $price */
+ $price = $this->specialPriceFactory->create();
+ $price->setSku('invalid')
+ ->setStoreId(0)
+ ->setPrice(5.0)
+ ->setPriceFrom($date->format('Y-m-d H:i:s'))
+ ->setPriceTo(
+ $date->modify('+1 day')
+ ->format('Y-m-d H:i:s')
+ );
+ $result = $this->model->update([$price]);
+ $this->assertCount(1, $result);
+ $this->assertStringContainsString(
+ 'The product that was requested doesn\'t exist.',
+ (string) $result[0]->getMessage()
+ );
+ $price->setSku('simple333');
+ $result = $this->model->update([$price]);
+ $this->assertCount(0, $result);
+ }
+}