Skip to content
This repository was archived by the owner on Apr 29, 2019. It is now read-only.

Commit 9bd3260

Browse files
author
Joan He
committed
Merge remote-tracking branch 'upstream/2.3-develop' into BugFixPR
2 parents e5cb829 + 6c529ec commit 9bd3260

File tree

48 files changed

+1394
-313
lines changed

Some content is hidden

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

48 files changed

+1394
-313
lines changed

app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ protected function doAddWebsiteNamesToResult()
831831
foreach ($this as $product) {
832832
if (isset($productWebsites[$product->getId()])) {
833833
$product->setData('websites', $productWebsites[$product->getId()]);
834+
$product->setData('website_ids', $productWebsites[$product->getId()]);
834835
}
835836
}
836837
return $this;
@@ -1126,11 +1127,11 @@ public function getSelectCountSql()
11261127
/**
11271128
* Get SQL for get record count
11281129
*
1129-
* @param \Magento\Framework\DB\Select $select
1130+
* @param Select $select
11301131
* @param bool $resetLeftJoins
1131-
* @return \Magento\Framework\DB\Select
1132+
* @return Select
11321133
*/
1133-
protected function _getSelectCountSql($select = null, $resetLeftJoins = true)
1134+
protected function _getSelectCountSql(?Select $select = null, $resetLeftJoins = true)
11341135
{
11351136
$this->_renderFilters();
11361137
$countSelect = $select === null ? $this->_getClearSelect() : $this->_buildClearSelect($select);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Observer;
9+
10+
use Magento\Catalog\Model\Indexer\Category\Product\Processor;
11+
use Magento\Framework\Event\Observer;
12+
use Magento\Framework\Event\ObserverInterface;
13+
14+
/**
15+
* Checks if a category has changed products and depends on indexer configuration.
16+
*/
17+
class CategoryProductIndexer implements ObserverInterface
18+
{
19+
/**
20+
* @var Processor
21+
*/
22+
private $processor;
23+
24+
/**
25+
* @param Processor $processor
26+
*/
27+
public function __construct(Processor $processor)
28+
{
29+
$this->processor = $processor;
30+
}
31+
32+
/**
33+
* @inheritdoc
34+
*/
35+
public function execute(Observer $observer): void
36+
{
37+
$productIds = $observer->getEvent()->getProductIds();
38+
if (!empty($productIds) && $this->processor->isIndexerScheduled()) {
39+
$this->processor->markIndexerAsInvalid();
40+
}
41+
}
42+
}

app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ class WebsitesTest extends AbstractModifierTest
7474
*/
7575
protected $storeViewMock;
7676

77+
/**
78+
* @inheritdoc
79+
*/
7780
protected function setUp()
7881
{
7982
parent::setUp();
@@ -90,14 +93,11 @@ protected function setUp()
9093
->disableOriginalConstructor()
9194
->getMock();
9295
$this->websiteRepositoryMock = $this->getMockBuilder(\Magento\Store\Api\WebsiteRepositoryInterface::class)
93-
->setMethods(['getList', 'getDefault'])
96+
->setMethods(['getList'])
9497
->getMockForAbstractClass();
9598
$this->websiteRepositoryMock->expects($this->any())
9699
->method('getDefault')
97100
->willReturn($this->websiteMock);
98-
$this->websiteRepositoryMock->expects($this->any())
99-
->method('getList')
100-
->willReturn([$this->websiteMock, $this->secondWebsiteMock]);
101101
$this->groupRepositoryMock = $this->getMockBuilder(\Magento\Store\Api\GroupRepositoryInterface::class)
102102
->setMethods(['getList'])
103103
->getMockForAbstractClass();
@@ -111,8 +111,10 @@ protected function setUp()
111111
->method('getWebsiteIds')
112112
->willReturn($this->assignedWebsites);
113113
$this->storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
114-
->setMethods(['isSingleStoreMode'])
114+
->setMethods(['isSingleStoreMode', 'getWesites'])
115115
->getMockForAbstractClass();
116+
$this->storeManagerMock->method('getWebsites')
117+
->willReturn([$this->websiteMock, $this->secondWebsiteMock]);
116118
$this->storeManagerMock->expects($this->any())
117119
->method('isSingleStoreMode')
118120
->willReturn(false);

app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ public function __construct(
290290
}
291291

292292
/**
293-
* {@inheritdoc}
293+
* @inheritdoc
294294
* @since 101.0.0
295295
*/
296296
public function modifyMeta(array $meta)
@@ -401,7 +401,7 @@ public function getContainerChildren(ProductAttributeInterface $attribute, $grou
401401
}
402402

403403
/**
404-
* {@inheritdoc}
404+
* @inheritdoc
405405
* @since 101.0.0
406406
*/
407407
public function modifyData(array $data)
@@ -532,7 +532,7 @@ private function getAttributes()
532532
/**
533533
* Loads attributes for specified groups at once
534534
*
535-
* @param AttributeGroupInterface[] ...$groups
535+
* @param AttributeGroupInterface[] $groups
536536
* @return @return ProductAttributeInterface[]
537537
*/
538538
private function loadAttributesForGroups(array $groups)
@@ -707,7 +707,8 @@ public function setupAttributeMeta(ProductAttributeInterface $attribute, $groupC
707707
}
708708

709709
/**
710-
* Returns attribute default value, based on db setting or setting in the system configuration
710+
* Returns attribute default value, based on db setting or setting in the system configuration.
711+
*
711712
* @param ProductAttributeInterface $attribute
712713
* @return null|string
713714
*/
@@ -742,6 +743,8 @@ private function convertOptionsValueToString(array $options) : array
742743
}
743744

744745
/**
746+
* Adds 'use default value' checkbox.
747+
*
745748
* @param ProductAttributeInterface $attribute
746749
* @param array $meta
747750
* @return array
@@ -944,6 +947,9 @@ private function canDisplayUseDefault(ProductAttributeInterface $attribute)
944947
$attributeCode = $attribute->getAttributeCode();
945948
/** @var Product $product */
946949
$product = $this->locator->getProduct();
950+
if ($product->isLockedAttribute($attributeCode)) {
951+
return false;
952+
}
947953

948954
if (isset($this->canDisplayUseDefault[$attributeCode])) {
949955
return $this->canDisplayUseDefault[$attributeCode];

app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function __construct(
8989
}
9090

9191
/**
92-
* {@inheritdoc}
92+
* @inheritdoc
9393
* @since 101.0.0
9494
*/
9595
public function modifyData(array $data)
@@ -117,7 +117,7 @@ public function modifyData(array $data)
117117
}
118118

119119
/**
120-
* {@inheritdoc}
120+
* @inheritdoc
121121
* @since 101.0.0
122122
*/
123123
public function modifyMeta(array $meta)
@@ -175,9 +175,11 @@ protected function getFieldsForFieldset()
175175
$label = __('Websites');
176176

177177
$defaultWebsiteId = $this->websiteRepository->getDefault()->getId();
178+
$isOnlyOneWebsiteAvailable = count($websitesList) === 1;
178179
foreach ($websitesList as $website) {
179180
$isChecked = in_array($website['id'], $websiteIds)
180-
|| ($defaultWebsiteId == $website['id'] && $isNewProduct);
181+
|| ($defaultWebsiteId == $website['id'] && $isNewProduct)
182+
|| $isOnlyOneWebsiteAvailable;
181183
$children[$website['id']] = [
182184
'arguments' => [
183185
'data' => [
@@ -331,6 +333,8 @@ protected function getWebsitesOptions()
331333
}
332334

333335
/**
336+
* Returns websites options list.
337+
*
334338
* @return array
335339
* @since 101.0.0
336340
*/
@@ -397,8 +401,9 @@ protected function getWebsitesList()
397401
$this->websitesList = [];
398402
$groupList = $this->groupRepository->getList();
399403
$storesList = $this->storeRepository->getList();
404+
$websiteList = $this->storeManager->getWebsites(true);
400405

401-
foreach ($this->websiteRepository->getList() as $website) {
406+
foreach ($websiteList as $website) {
402407
$websiteId = $website->getId();
403408
if (!$websiteId) {
404409
continue;

app/code/Magento/Catalog/etc/adminhtml/events.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@
99
<event name="cms_wysiwyg_images_static_urls_allowed">
1010
<observer name="catalog_wysiwyg" instance="Magento\Catalog\Observer\CatalogCheckIsUsingStaticUrlsAllowedObserver" />
1111
</event>
12+
<event name="catalog_category_change_products">
13+
<observer name="category_product_indexer" instance="Magento\Catalog\Observer\CategoryProductIndexer"/>
14+
</event>
1215
</config>

app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@
1717
use Magento\CatalogInventory\Model\Stock;
1818
use Magento\Framework\Event\Observer;
1919
use Magento\Framework\Exception\LocalizedException;
20+
use Magento\Quote\Model\Quote\Item;
2021

2122
/**
23+
* Quote item quantity validator.
24+
*
2225
* @api
2326
* @since 100.0.2
27+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2428
*/
2529
class QuantityValidator
2630
{
@@ -67,8 +71,7 @@ public function __construct(
6771
* Add error information to Quote Item
6872
*
6973
* @param \Magento\Framework\DataObject $result
70-
* @param \Magento\Quote\Model\Quote\Item $quoteItem
71-
* @param bool $removeError
74+
* @param Item $quoteItem
7275
* @return void
7376
*/
7477
private function addErrorInfoToQuote($result, $quoteItem)
@@ -100,7 +103,7 @@ private function addErrorInfoToQuote($result, $quoteItem)
100103
*/
101104
public function validate(Observer $observer)
102105
{
103-
/* @var $quoteItem \Magento\Quote\Model\Quote\Item */
106+
/* @var $quoteItem Item */
104107
$quoteItem = $observer->getEvent()->getItem();
105108
if (!$quoteItem ||
106109
!$quoteItem->getProductId() ||
@@ -175,35 +178,11 @@ public function validate(Observer $observer)
175178
$qty = $product->getTypeInstance()->prepareQuoteItemQty($qty, $product);
176179
$quoteItem->setData('qty', $qty);
177180
if ($stockStatus) {
178-
$result = $this->stockState->checkQtyIncrements(
179-
$product->getId(),
180-
$qty,
181-
$product->getStore()->getWebsiteId()
182-
);
183-
if ($result->getHasError()) {
184-
$quoteItem->addErrorInfo(
185-
'cataloginventory',
186-
Data::ERROR_QTY_INCREMENTS,
187-
$result->getMessage()
188-
);
189-
190-
$quoteItem->getQuote()->addErrorInfo(
191-
$result->getQuoteMessageIndex(),
192-
'cataloginventory',
193-
Data::ERROR_QTY_INCREMENTS,
194-
$result->getQuoteMessage()
195-
);
196-
} else {
197-
// Delete error from item and its quote, if it was set due to qty problems
198-
$this->_removeErrorsFromQuoteAndItem(
199-
$quoteItem,
200-
Data::ERROR_QTY_INCREMENTS
201-
);
202-
}
181+
$this->checkOptionsQtyIncrements($quoteItem, $options);
203182
}
183+
204184
// variable to keep track if we have previously encountered an error in one of the options
205185
$removeError = true;
206-
207186
foreach ($options as $option) {
208187
$result = $option->getStockStateResult();
209188
if ($result->getHasError()) {
@@ -228,10 +207,47 @@ public function validate(Observer $observer)
228207
}
229208
}
230209

210+
/**
211+
* Verifies product options quantity increments.
212+
*
213+
* @param Item $quoteItem
214+
* @param array $options
215+
* @return void
216+
*/
217+
private function checkOptionsQtyIncrements(Item $quoteItem, array $options): void
218+
{
219+
$removeErrors = true;
220+
foreach ($options as $option) {
221+
$result = $this->stockState->checkQtyIncrements(
222+
$option->getProduct()->getId(),
223+
$quoteItem->getData('qty'),
224+
$option->getProduct()->getStore()->getWebsiteId()
225+
);
226+
if ($result->getHasError()) {
227+
$quoteItem->getQuote()->addErrorInfo(
228+
$result->getQuoteMessageIndex(),
229+
'cataloginventory',
230+
Data::ERROR_QTY_INCREMENTS,
231+
$result->getQuoteMessage()
232+
);
233+
234+
$removeErrors = false;
235+
}
236+
}
237+
238+
if ($removeErrors) {
239+
// Delete error from item and its quote, if it was set due to qty problems
240+
$this->_removeErrorsFromQuoteAndItem(
241+
$quoteItem,
242+
Data::ERROR_QTY_INCREMENTS
243+
);
244+
}
245+
}
246+
231247
/**
232248
* Removes error statuses from quote and item, set by this observer
233249
*
234-
* @param \Magento\Quote\Model\Quote\Item $item
250+
* @param Item $item
235251
* @param int $code
236252
* @return void
237253
*/

app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
use Magento\CatalogInventory\Api\StockStateInterface;
1010
use Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\QuoteItemQtyList;
1111

12+
/**
13+
* Quote item option initializer.
14+
*/
1215
class Option
1316
{
1417
/**
@@ -67,10 +70,6 @@ public function getStockItem(
6770
* define that stock item is child for composite product
6871
*/
6972
$stockItem->setIsChildItem(true);
70-
/**
71-
* don't check qty increments value for option product
72-
*/
73-
$stockItem->setSuppressCheckQtyIncrements(true);
7473

7574
return $stockItem;
7675
}

app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ public function testInitializeWhenResultIsDecimalGetBackordersMessageHasOptionQt
151151
$this->optionMock->expects($this->any())->method('getProduct')->will($this->returnValue($this->productMock));
152152

153153
$this->stockItemMock->expects($this->once())->method('setIsChildItem')->with(true);
154-
$this->stockItemMock->expects($this->once())->method('setSuppressCheckQtyIncrements')->with(true);
155154
$this->stockItemMock->expects($this->once())->method('getItemId')->will($this->returnValue(true));
156155

157156
$this->stockRegistry
@@ -222,7 +221,6 @@ public function testInitializeWhenResultNotDecimalGetBackordersMessageHasOptionQ
222221
$this->optionMock->expects($this->any())->method('getProduct')->will($this->returnValue($this->productMock));
223222

224223
$this->stockItemMock->expects($this->once())->method('setIsChildItem')->with(true);
225-
$this->stockItemMock->expects($this->once())->method('setSuppressCheckQtyIncrements')->with(true);
226224
$this->stockItemMock->expects($this->once())->method('getItemId')->will($this->returnValue(true));
227225

228226
$this->stockRegistry

0 commit comments

Comments
 (0)