Skip to content

Commit efc2907

Browse files
authored
Merge branch '2.4-develop' into graphql-api-enhancements
2 parents 4cf31c4 + 36d4d6f commit efc2907

File tree

188 files changed

+10877
-580
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

188 files changed

+10877
-580
lines changed

app/code/Magento/Amqp/Setup/ConfigOptionsList.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
*/
66
namespace Magento\Amqp\Setup;
77

8+
use Magento\Framework\App\DeploymentConfig;
89
use Magento\Framework\Config\Data\ConfigData;
910
use Magento\Framework\Config\File\ConfigFilePool;
1011
use Magento\Framework\Setup\ConfigOptionsListInterface;
1112
use Magento\Framework\Setup\Option\TextConfigOption;
12-
use Magento\Framework\App\DeploymentConfig;
1313

1414
/**
1515
* Deployment configuration options needed for Setup application
@@ -26,6 +26,7 @@ class ConfigOptionsList implements ConfigOptionsListInterface
2626
public const INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST = 'amqp-virtualhost';
2727
public const INPUT_KEY_QUEUE_AMQP_SSL = 'amqp-ssl';
2828
public const INPUT_KEY_QUEUE_AMQP_SSL_OPTIONS = 'amqp-ssl-options';
29+
public const INPUT_KEY_QUEUE_DEFAULT_CONNECTION ='queue-default-connection';
2930

3031
/**
3132
* Path to the values in the deployment config
@@ -203,6 +204,11 @@ public function validate(array $options, DeploymentConfig $deploymentConfig)
203204
if (!$result) {
204205
$errors[] = "Could not connect to the Amqp Server.";
205206
}
207+
208+
if (isset($options[self::INPUT_KEY_QUEUE_DEFAULT_CONNECTION])
209+
&& $options[self::INPUT_KEY_QUEUE_DEFAULT_CONNECTION] !== 'amqp') {
210+
$errors = [];
211+
}
206212
}
207213

208214
return $errors;

app/code/Magento/AsyncConfig/etc/queue_publisher.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd">
9-
<publisher topic="async_config.saveConfig"/>
9+
<publisher topic="async_config.saveConfig" queue="saveConfig"/>
1010
</config>

app/code/Magento/AsynchronousOperations/Model/MassConsumer.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
namespace Magento\AsynchronousOperations\Model;
99

10+
use Magento\Framework\App\ObjectManager;
1011
use Magento\Framework\MessageQueue\CallbackInvokerInterface;
12+
use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfig;
1113
use Magento\Framework\MessageQueue\ConsumerConfigurationInterface;
1214
use Magento\Framework\MessageQueue\ConsumerInterface;
1315
use Magento\Framework\MessageQueue\EnvelopeInterface;
@@ -41,24 +43,32 @@ class MassConsumer implements ConsumerInterface
4143
*/
4244
private $registry;
4345

46+
/**
47+
* @var ConsumerConfig
48+
*/
49+
private $consumerConfig;
50+
4451
/**
4552
* Initialize dependencies.
4653
*
4754
* @param CallbackInvokerInterface $invoker
4855
* @param ConsumerConfigurationInterface $configuration
4956
* @param MassConsumerEnvelopeCallbackFactory $massConsumerEnvelopeCallback
5057
* @param Registry $registry
58+
* @param ConsumerConfig|null $consumerConfig
5159
*/
5260
public function __construct(
5361
CallbackInvokerInterface $invoker,
5462
ConsumerConfigurationInterface $configuration,
5563
MassConsumerEnvelopeCallbackFactory $massConsumerEnvelopeCallback,
56-
Registry $registry
64+
Registry $registry,
65+
?ConsumerConfig $consumerConfig = null
5766
) {
5867
$this->invoker = $invoker;
5968
$this->configuration = $configuration;
6069
$this->massConsumerEnvelopeCallback = $massConsumerEnvelopeCallback;
6170
$this->registry = $registry;
71+
$this->consumerConfig = $consumerConfig ?: ObjectManager::getInstance()->get(ConsumerConfig::class);
6272
}
6373

6474
/**

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,22 @@ private function validateProductAttributes(array $attributesData): void
229229
$product = $this->productFactory->create();
230230
$product->setData($attributesData);
231231

232-
foreach (array_keys($attributesData) as $attributeCode) {
233-
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
234-
$attribute->getBackend()->validate($product);
232+
// Ensure Special Price From Date cannot exceed To Date during mass update
233+
if (array_key_exists('special_from_date', $attributesData)
234+
|| array_key_exists('special_to_date', $attributesData)) {
235+
$this->eavConfig
236+
->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'special_from_date')
237+
->setMaxValue($product->getSpecialToDate());
238+
}
239+
240+
try {
241+
foreach (array_keys($attributesData) as $attributeCode) {
242+
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
243+
$attribute->getBackend()->validate($product);
244+
}
245+
} catch (\Magento\Eav\Model\Entity\Attribute\Exception $e) {
246+
// Re-throw as LocalizedException so the specific validation message is displayed
247+
throw new LocalizedException(__($e->getMessage()));
235248
}
236249
}
237250

app/code/Magento/Catalog/Model/ProductRepository.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ public function get($sku, $editMode = false, $storeId = null, $forceReload = fal
285285
$productId = $this->resourceModel->getIdBySku($sku);
286286
if (!$productId) {
287287
throw new NoSuchEntityException(
288-
__("The product that was requested doesn't exist. Verify the product and try again.")
288+
__('The product with SKU "%1" does not exist.', $sku)
289289
);
290290
}
291291
if ($editMode) {
@@ -319,7 +319,7 @@ public function getById($productId, $editMode = false, $storeId = null, $forceRe
319319
$product->load($productId);
320320
if (!$product->getId()) {
321321
throw new NoSuchEntityException(
322-
__("The product that was requested doesn't exist. Verify the product and try again.")
322+
__('The product with ID "%1" does not exist.', $productId)
323323
);
324324
}
325325
$this->cacheProduct($cacheKey, $product);
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
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="AdminUnassignAllWebsitesFromProductTest">
12+
<annotations>
13+
<features value="Catalog"/>
14+
<stories value="Create multi-website and multi-store, assign product to both, then unassign all websites and save."/>
15+
<title value="Unassign all websites from a product and set visibility to Not Visible Individually"/>
16+
<description value="Validate Removing a product from all websites in admin the product is saved successfully"/>
17+
<testCaseId value="AC-3653"/>
18+
<severity value="AVERAGE"/>
19+
<group value="catalog"/>
20+
</annotations>
21+
<before>
22+
<!-- Pre-condition 1: Create product -->
23+
<createData entity="defaultSimpleProduct" stepKey="createSimpleProduct"/>
24+
<!-- Pre-condition 2: Create a second website, store and store view -->
25+
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
26+
<actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createSecondWebsite">
27+
<argument name="newWebsiteName" value="{{secondCustomWebsite.name}}"/>
28+
<argument name="websiteCode" value="{{secondCustomWebsite.code}}"/>
29+
</actionGroup>
30+
<actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createSecondStore">
31+
<argument name="website" value="{{secondCustomWebsite.name}}"/>
32+
<argument name="storeGroupName" value="{{SecondStoreGroupUnique.name}}"/>
33+
<argument name="storeGroupCode" value="{{SecondStoreGroupUnique.code}}"/>
34+
</actionGroup>
35+
<actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createSecondStoreView">
36+
<argument name="StoreGroup" value="SecondStoreGroupUnique"/>
37+
<argument name="customStore" value="SecondStoreUnique"/>
38+
</actionGroup>
39+
</before>
40+
<after>
41+
<!-- Delete product -->
42+
<actionGroup ref="DeleteProductBySkuActionGroup" stepKey="deleteProduct">
43+
<argument name="sku" value="{{defaultSimpleProduct.sku}}"/>
44+
</actionGroup>
45+
<!-- Delete the second website -->
46+
<actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteSecondWebsite">
47+
<argument name="websiteName" value="{{secondCustomWebsite.name}}"/>
48+
</actionGroup>
49+
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
50+
</after>
51+
<!-- Step 1: Go to Admin panel, navigate to product -->
52+
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="openProductGrid"/>
53+
<actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="goToProductEditPage">
54+
<argument name="productId" value="$$createSimpleProduct.id$$"/>
55+
</actionGroup>
56+
<actionGroup ref="SelectProductInWebsitesActionGroup" stepKey="addProductToWebsite">
57+
<argument name="website" value="{{secondCustomWebsite.name}}"/>
58+
</actionGroup>
59+
<actionGroup ref="SelectProductInWebsitesActionGroup" stepKey="addProductToWeb">
60+
<argument name="website" value="{{_defaultWebsite.name}}"/>
61+
</actionGroup>
62+
<actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct"/>
63+
<!-- Step 2: Edit the product and set the visibility to "not visible individually", navigate to products and website section and uncheck all the websites and save the product-->
64+
<actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="goToProductEditPageAgain">
65+
<argument name="productId" value="$$createSimpleProduct.id$$"/>
66+
</actionGroup>
67+
<!-- Set visibility to "not visible individually" -->
68+
<selectOption selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductNotVisibleIndividually.visibility}}" stepKey="setVisibilityNotVisibleIndividually"/>
69+
<!-- Uncheck all websites -->
70+
<actionGroup ref="UnassignWebsiteFromProductActionGroup" stepKey="unassignCreatedWebsiteInProduct">
71+
<argument name="website" value="{{secondCustomWebsite.name}}"/>
72+
</actionGroup>
73+
<actionGroup ref="UnassignWebsiteFromProductActionGroup" stepKey="unassignWebsiteInProduct">
74+
<argument name="website" value="{{_defaultWebsite.name}}"/>
75+
</actionGroup>
76+
<!-- Save the product -->
77+
<actionGroup ref="AdminProductFormSaveActionGroup" stepKey="saveProductAfterUpdate"/>
78+
<!-- Step 3: Verify the product is saved successfully -->
79+
<waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForSuccessMessage"/>
80+
</test>
81+
</tests>

0 commit comments

Comments
 (0)