Skip to content

Commit 7c6b636

Browse files
authored
Merge pull request #6709 from magento-tsg/2.4-develop-pr135
[Arrows] Fixes for 2.4 (pr135) (2.4-develop)
2 parents 8b56d34 + 4609a2c commit 7c6b636

File tree

12 files changed

+258
-43
lines changed

12 files changed

+258
-43
lines changed

app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ define([
6464
click: function () {
6565
self.onConfirmBtn();
6666
}
67-
}]
67+
}],
68+
closed: function () {
69+
self.clean('window');
70+
},
6871
});
6972
});
7073
},
@@ -406,6 +409,7 @@ define([
406409
this.blockMsgError.innerHTML = response.message;
407410
this._showWindow();
408411

412+
jQuery(this.blockForm).trigger('processStop');
409413
return false;
410414
}
411415
}

app/code/Magento/CatalogGraphQl/Model/Category/DepthCalculator.php

+24-10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Magento\CatalogGraphQl\Model\Category;
99

10+
use GraphQL\Language\AST\Node;
1011
use GraphQL\Language\AST\FieldNode;
1112
use GraphQL\Language\AST\InlineFragmentNode;
1213
use GraphQL\Language\AST\NodeKind;
@@ -26,22 +27,35 @@ class DepthCalculator
2627
*/
2728
public function calculate(ResolveInfo $resolveInfo, FieldNode $fieldNode) : int
2829
{
29-
$selections = $fieldNode->selectionSet->selections ?? [];
30+
return $this->calculateRecursive($resolveInfo, $fieldNode);
31+
}
32+
33+
/**
34+
* Calculate recursive the total depth of a category tree inside a GraphQL request
35+
*
36+
* @param ResolveInfo $resolveInfo
37+
* @param Node $node
38+
* @return int
39+
*/
40+
private function calculateRecursive(ResolveInfo $resolveInfo, Node $node) : int
41+
{
42+
if ($node->kind === NodeKind::FRAGMENT_SPREAD) {
43+
$selections = isset($resolveInfo->fragments[$node->name->value]) ?
44+
$resolveInfo->fragments[$node->name->value]->selectionSet->selections : [];
45+
} else {
46+
$selections = $node->selectionSet->selections ?? [];
47+
}
3048
$depth = count($selections) ? 1 : 0;
3149
$childrenDepth = [0];
32-
foreach ($selections as $node) {
33-
if (isset($node->alias) && null !== $node->alias) {
50+
foreach ($selections as $subNode) {
51+
if (isset($subNode->alias) && null !== $subNode->alias) {
3452
continue;
3553
}
3654

37-
if ($node->kind === NodeKind::INLINE_FRAGMENT) {
38-
$childrenDepth[] = $this->addInlineFragmentDepth($resolveInfo, $node);
39-
} elseif ($node->kind === NodeKind::FRAGMENT_SPREAD && isset($resolveInfo->fragments[$node->name->value])) {
40-
foreach ($resolveInfo->fragments[$node->name->value]->selectionSet->selections as $spreadNode) {
41-
$childrenDepth[] = $this->calculate($resolveInfo, $spreadNode);
42-
}
55+
if ($subNode->kind === NodeKind::INLINE_FRAGMENT) {
56+
$childrenDepth[] = $this->addInlineFragmentDepth($resolveInfo, $subNode);
4357
} else {
44-
$childrenDepth[] = $this->calculate($resolveInfo, $node);
58+
$childrenDepth[] = $this->calculateRecursive($resolveInfo, $subNode);
4559
}
4660
}
4761

app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php

+13-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Magento\Framework\Stdlib\DateTime\DateTime;
2626
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
2727
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
28+
use Psr\Log\LoggerInterface as PsrLogger;
2829

2930
/**
3031
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -98,8 +99,11 @@ class StockItemRepository implements StockItemRepositoryInterface
9899
protected $productCollectionFactory;
99100

100101
/**
101-
* Constructor
102-
*
102+
* @var PsrLogger
103+
*/
104+
private $psrLogger;
105+
106+
/**
103107
* @param StockConfigurationInterface $stockConfiguration
104108
* @param StockStateProviderInterface $stockStateProvider
105109
* @param StockItemResource $resource
@@ -111,7 +115,8 @@ class StockItemRepository implements StockItemRepositoryInterface
111115
* @param TimezoneInterface $localeDate
112116
* @param Processor $indexProcessor
113117
* @param DateTime $dateTime
114-
* @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory|null $collectionFactory
118+
* @param CollectionFactory|null $productCollectionFactory
119+
* @param PsrLogger|null $psrLogger
115120
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
116121
*/
117122
public function __construct(
@@ -126,7 +131,8 @@ public function __construct(
126131
TimezoneInterface $localeDate,
127132
Processor $indexProcessor,
128133
DateTime $dateTime,
129-
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory = null
134+
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory = null,
135+
PsrLogger $psrLogger = null
130136
) {
131137
$this->stockConfiguration = $stockConfiguration;
132138
$this->stockStateProvider = $stockStateProvider;
@@ -141,6 +147,8 @@ public function __construct(
141147
$this->dateTime = $dateTime;
142148
$this->productCollectionFactory = $productCollectionFactory ?: ObjectManager::getInstance()
143149
->get(CollectionFactory::class);
150+
$this->psrLogger = $psrLogger ?: ObjectManager::getInstance()
151+
->get(PsrLogger::class);
144152
}
145153

146154
/**
@@ -184,6 +192,7 @@ public function save(\Magento\CatalogInventory\Api\Data\StockItemInterface $stoc
184192

185193
$this->resource->save($stockItem);
186194
} catch (\Exception $exception) {
195+
$this->psrLogger->error($exception->getMessage());
187196
throw new CouldNotSaveException(__('The stock item was unable to be saved. Please try again.'), $exception);
188197
}
189198
return $stockItem;

app/code/Magento/CatalogInventory/Model/StockStateProvider.php

+17-18
Original file line numberDiff line numberDiff line change
@@ -105,47 +105,46 @@ public function verifyNotification(StockItemInterface $stockItem)
105105
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
106106
* @SuppressWarnings(PHPMD.NPathComplexity)
107107
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
108+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
108109
*/
109110
public function checkQuoteItemQty(StockItemInterface $stockItem, $qty, $summaryQty, $origQty = 0)
110111
{
111112
$result = $this->objectFactory->create();
112113
$result->setHasError(false);
113-
114114
$qty = $this->getNumber($qty);
115-
116-
/**
117-
* Check quantity type
118-
*/
119-
$result->setItemIsQtyDecimal($stockItem->getIsQtyDecimal());
120-
if (!$stockItem->getIsQtyDecimal()) {
121-
$result->setHasQtyOptionUpdate(true);
122-
$qty = (int) $qty ?: 1;
123-
/**
124-
* Adding stock data to quote item
125-
*/
126-
$result->setItemQty($qty);
127-
$result->setOrigQty((int)$this->getNumber($origQty) ?: 1);
128-
}
115+
$quoteMessage = __('Please correct the quantity for some products.');
129116

130117
if ($stockItem->getMinSaleQty() && $qty < $stockItem->getMinSaleQty()) {
131118
$result->setHasError(true)
132119
->setMessage(__('The fewest you may purchase is %1.', $stockItem->getMinSaleQty() * 1))
133120
->setErrorCode('qty_min')
134-
->setQuoteMessage(__('Please correct the quantity for some products.'))
121+
->setQuoteMessage($quoteMessage)
135122
->setQuoteMessageIndex('qty');
136123
return $result;
137124
}
138125

139126
if ($stockItem->getMaxSaleQty() && $qty > $stockItem->getMaxSaleQty()) {
140127
$result->setHasError(true)
141-
->setMessage(__('The most you may purchase is %1.', $stockItem->getMaxSaleQty() * 1))
128+
->setMessage(__('The requested qty exceeds the maximum qty allowed in shopping cart'))
142129
->setErrorCode('qty_max')
143-
->setQuoteMessage(__('Please correct the quantity for some products.'))
130+
->setQuoteMessage($quoteMessage)
144131
->setQuoteMessageIndex('qty');
145132
return $result;
146133
}
147134

148135
$result->addData($this->checkQtyIncrements($stockItem, $qty)->getData());
136+
137+
$result->setItemIsQtyDecimal($stockItem->getIsQtyDecimal());
138+
if (!$stockItem->getIsQtyDecimal() && (floor($qty) !== $qty)) {
139+
$result->setHasError(true)
140+
->setMessage(__('You cannot use decimal quantity for this product.'))
141+
->setErrorCode('qty_decimal')
142+
->setQuoteMessage($quoteMessage)
143+
->setQuoteMessageIndex('qty');
144+
145+
return $result;
146+
}
147+
149148
if ($result->getHasError()) {
150149
return $result;
151150
}

app/code/Magento/CatalogInventory/Test/Unit/Model/Spi/StockStateProviderTest.php

+9-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
use PHPUnit\Framework\TestCase;
2222

2323
/**
24+
* Unit tests for \Magento\CatalogInventory\Model\StockStateProvider class.
25+
*
2426
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2527
*/
2628
class StockStateProviderTest extends TestCase
@@ -115,6 +117,9 @@ class StockStateProviderTest extends TestCase
115117
'getProductName',
116118
];
117119

120+
/**
121+
* @inheritDoc
122+
*/
118123
protected function setUp(): void
119124
{
120125
$this->objectManagerHelper = new ObjectManagerHelper($this);
@@ -383,7 +388,7 @@ protected function getVariations()
383388
'suggestQty' => 51,
384389
'getStockQty' => $stockQty,
385390
'checkQtyIncrements' => false,
386-
'checkQuoteItemQty' => false,
391+
'checkQuoteItemQty' => true,
387392
],
388393
],
389394
[
@@ -411,7 +416,7 @@ protected function getVariations()
411416
'getStockQty' => $stockQty,
412417
'checkQtyIncrements' => false,
413418
'checkQuoteItemQty' => true,
414-
]
419+
],
415420
],
416421
[
417422
'values' => [
@@ -438,8 +443,8 @@ protected function getVariations()
438443
'getStockQty' => null,
439444
'checkQtyIncrements' => false,
440445
'checkQuoteItemQty' => true,
441-
]
442-
]
446+
],
447+
],
443448
];
444449
}
445450

app/code/Magento/CatalogInventory/i18n/en_US.csv

+2
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,5 @@ Stock,Stock
7171
"Qty Uses Decimals","Qty Uses Decimals"
7272
"Allow Multiple Boxes for Shipping","Allow Multiple Boxes for Shipping"
7373
"Done","Done"
74+
"The requested qty exceeds the maximum qty allowed in shopping cart","The requested qty exceeds the maximum qty allowed in shopping cart"
75+
"You cannot use decimal quantity for this product.","You cannot use decimal quantity for this product."

app/code/Magento/Checkout/view/frontend/web/js/view/form/element/email.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,13 @@ define([
161161
return valid;
162162
}
163163

164-
validator = loginForm.validate();
164+
if (loginForm.is(':visible')) {
165+
validator = loginForm.validate();
165166

166-
return validator.check(usernameSelector);
167+
return validator.check(usernameSelector);
168+
}
169+
170+
return true;
167171
},
168172

169173
/**

app/code/Magento/Elasticsearch/Model/ResourceModel/Index.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\Elasticsearch\Model\ResourceModel;
77

88
use Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory;
9+
use Magento\Framework\Exception\NoSuchEntityException;
910
use Magento\Framework\Model\ResourceModel\Db\Context;
1011
use Magento\Store\Model\StoreManagerInterface;
1112
use Magento\Catalog\Api\ProductRepositoryInterface;
@@ -137,7 +138,11 @@ public function getFullCategoryProductIndexData($storeId = null, $productIds = n
137138

138139
foreach ($categoryPositions as $productId => $positions) {
139140
foreach ($positions as $categoryId => $position) {
140-
$category = $this->categoryRepository->get($categoryId, $storeId);
141+
try {
142+
$category = $this->categoryRepository->get($categoryId, $storeId);
143+
} catch (NoSuchEntityException $e) {
144+
continue;
145+
}
141146
$categoryName = $category->getName();
142147
$categoryData[$productId][] = [
143148
'id' => $categoryId,

dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php

+45
Original file line numberDiff line numberDiff line change
@@ -842,4 +842,49 @@ public function testFilterCategoryNamedFragment()
842842
$this->assertEquals($result['categoryList'][0]['uid'], base64_encode('6'));
843843
$this->assertEquals($result['categoryList'][0]['url_path'], 'category-2');
844844
}
845+
846+
/**
847+
* Test when there is recursive category node fragment
848+
*
849+
* @magentoApiDataFixture Magento/Catalog/_files/categories.php
850+
*/
851+
public function testFilterCategoryRecursiveFragment() : void
852+
{
853+
$query = <<<'QUERY'
854+
query GetCategoryTree($filters: CategoryFilterInput!) {
855+
categoryList(filters: $filters) {
856+
...recursiveCategoryNode
857+
}
858+
}
859+
860+
fragment recursiveCategoryNode on CategoryTree {
861+
...categoryNode
862+
children {
863+
...categoryNode
864+
}
865+
}
866+
867+
fragment categoryNode on CategoryTree {
868+
id
869+
}
870+
QUERY;
871+
$variables = [
872+
'filters' => [
873+
'ids' => [
874+
'eq' => '2',
875+
],
876+
],
877+
];
878+
$result = $this->graphQlQuery($query, $variables);
879+
$this->assertArrayNotHasKey('errors', $result);
880+
$this->assertCount(1, $result['categoryList']);
881+
$this->assertCount(2, $result['categoryList'][0]);
882+
$this->assertArrayHasKey('id', $result['categoryList'][0]);
883+
$this->assertArrayHasKey('children', $result['categoryList'][0]);
884+
$this->assertEquals($result['categoryList'][0]['id'], '2');
885+
$this->assertCount(7, $result['categoryList'][0]['children']);
886+
$this->assertCount(1, $result['categoryList'][0]['children'][0]);
887+
$this->assertArrayHasKey('id', $result['categoryList'][0]['children'][0]);
888+
$this->assertEquals($result['categoryList'][0]['children'][0]['id'], '3');
889+
}
845890
}

dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php

+28
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
use Magento\TestFramework\TestCase\AbstractBackendController;
2323
use Magento\Catalog\Model\Product\Attribute\LayoutUpdateManager;
2424
use Magento\Catalog\Model\Product\Type;
25+
use Magento\Catalog\Api\ProductRepositoryInterface;
26+
use Magento\Catalog\Model\Category;
2527

2628
/**
2729
* Test class for Product adminhtml actions
@@ -46,6 +48,11 @@ class ProductTest extends AbstractBackendController
4648
*/
4749
private $resourceModel;
4850

51+
/**
52+
* @var ProductRepositoryInterface
53+
*/
54+
private $productRepository;
55+
4956
/**
5057
* @inheritDoc
5158
*/
@@ -62,6 +69,7 @@ protected function setUp(): void
6269
$this->aclBuilder = Bootstrap::getObjectManager()->get(Builder::class);
6370
$this->repositoryFactory = Bootstrap::getObjectManager()->get(ProductRepositoryFactory::class);
6471
$this->resourceModel = Bootstrap::getObjectManager()->get(ProductResource::class);
72+
$this->productRepository = $this->_objectManager->get(ProductRepositoryInterface::class);
6573
}
6674

6775
/**
@@ -677,4 +685,24 @@ public function testSaveActionWithInvalidUrlKey(array $postData)
677685
);
678686
$this->assertRedirect($this->stringContains('/backend/catalog/product/new'));
679687
}
688+
689+
/**
690+
* @magentoDataFixture Magento/Catalog/_files/category_product.php
691+
* @magentoDbIsolation disabled
692+
* @magentoAppArea adminhtml
693+
*/
694+
public function testSaveProductWithDeletedCategory(): void
695+
{
696+
$category = $this->_objectManager->get(Category::class);
697+
$category->load(333);
698+
$category->delete();
699+
$product = $this->productRepository->get('simple333');
700+
$this->productRepository->save($product);
701+
$this->getRequest()->setMethod(HttpRequest::METHOD_POST);
702+
$this->dispatch('backend/catalog/product/save/id/' . $product->getEntityId());
703+
$this->assertSessionMessages(
704+
$this->equalTo([(string)__('You saved the product.')]),
705+
MessageInterface::TYPE_SUCCESS
706+
);
707+
}
680708
}

0 commit comments

Comments
 (0)