Skip to content

Commit 37c34a3

Browse files
Merge branch '2.4-develop' into 2.4-develop-prs
2 parents c88224b + e71f154 commit 37c34a3

File tree

21 files changed

+527
-63
lines changed

21 files changed

+527
-63
lines changed

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -656,11 +656,7 @@ public function getProductsIdsBySkus(array $productSkuList)
656656
*/
657657
private function getResultKey(string $sku, array $productSkuList): string
658658
{
659-
$key = array_search(strtolower($sku), array_map('strtolower', $productSkuList));
660-
if ($key !== false) {
661-
$sku = $productSkuList[$key];
662-
}
663-
return $sku;
659+
return in_array(strtolower($sku), array_map('strtolower', $productSkuList)) ? $sku : '';
664660
}
665661

666662
/**

app/code/Magento/CatalogGraphQl/DataProvider/Product/SearchCriteriaBuilder.php

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,23 @@
88
namespace Magento\CatalogGraphQl\DataProvider\Product;
99

1010
use Magento\Catalog\Api\Data\EavAttributeInterface;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\Catalog\Model\Product\Visibility;
13+
use Magento\Eav\Model\Config;
1114
use Magento\Framework\Api\FilterBuilder;
1215
use Magento\Framework\Api\Search\FilterGroupBuilder;
1316
use Magento\Framework\Api\Search\SearchCriteriaInterface;
1417
use Magento\Framework\Api\SortOrder;
18+
use Magento\Framework\Api\SortOrderBuilder;
1519
use Magento\Framework\App\Config\ScopeConfigInterface;
20+
use Magento\Framework\App\ObjectManager;
1621
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\Builder;
17-
use Magento\Catalog\Model\Product\Visibility;
18-
use Magento\Framework\Api\SortOrderBuilder;
1922

2023
/**
2124
* Build search criteria
25+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2226
*/
27+
2328
class SearchCriteriaBuilder
2429
{
2530
/**
@@ -51,28 +56,36 @@ class SearchCriteriaBuilder
5156
*/
5257
private $sortOrderBuilder;
5358

59+
/**
60+
* @var Config
61+
*/
62+
private Config $eavConfig;
63+
5464
/**
5565
* @param Builder $builder
5666
* @param ScopeConfigInterface $scopeConfig
5767
* @param FilterBuilder $filterBuilder
5868
* @param FilterGroupBuilder $filterGroupBuilder
5969
* @param Visibility $visibility
6070
* @param SortOrderBuilder $sortOrderBuilder
71+
* @param Config $eavConfig
6172
*/
6273
public function __construct(
6374
Builder $builder,
6475
ScopeConfigInterface $scopeConfig,
6576
FilterBuilder $filterBuilder,
6677
FilterGroupBuilder $filterGroupBuilder,
6778
Visibility $visibility,
68-
SortOrderBuilder $sortOrderBuilder
79+
SortOrderBuilder $sortOrderBuilder = null,
80+
Config $eavConfig = null
6981
) {
7082
$this->scopeConfig = $scopeConfig;
7183
$this->filterBuilder = $filterBuilder;
7284
$this->filterGroupBuilder = $filterGroupBuilder;
7385
$this->builder = $builder;
7486
$this->visibility = $visibility;
75-
$this->sortOrderBuilder = $sortOrderBuilder;
87+
$this->sortOrderBuilder = $sortOrderBuilder ?? ObjectManager::getInstance()->get(SortOrderBuilder::class);
88+
$this->eavConfig = $eavConfig ?? ObjectManager::getInstance()->get(Config::class);
7689
}
7790

7891
/**
@@ -87,9 +100,13 @@ public function build(array $args, bool $includeAggregation): SearchCriteriaInte
87100
$searchCriteria = $this->builder->build('products', $args);
88101
$isSearch = !empty($args['search']);
89102
$this->updateRangeFilters($searchCriteria);
90-
91103
if ($includeAggregation) {
92-
$this->preparePriceAggregation($searchCriteria);
104+
$attributeData = $this->eavConfig->getAttribute(Product::ENTITY, 'price');
105+
$priceOptions = $attributeData->getData();
106+
107+
if ($priceOptions['is_filterable'] != 0) {
108+
$this->preparePriceAggregation($searchCriteria);
109+
}
93110
$requestName = 'graphql_product_search_with_aggregation';
94111
} else {
95112
$requestName = 'graphql_product_search';
@@ -142,7 +159,7 @@ private function addEntityIdSort(SearchCriteriaInterface $searchCriteria): void
142159
{
143160
$sortOrderArray = $searchCriteria->getSortOrders();
144161
$sortDir = SortOrder::SORT_DESC;
145-
if (count($sortOrderArray) > 0) {
162+
if (is_array($sortOrderArray) && count($sortOrderArray) > 0) {
146163
$sortOrder = end($sortOrderArray);
147164
// in the case the last sort order is by position, sort IDs in descendent order
148165
$sortDir = $sortOrder->getField() === EavAttributeInterface::POSITION
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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\CatalogGraphQl\Test\Unit\DataProvider\Product;
9+
10+
use Magento\Catalog\Model\Product;
11+
use Magento\Catalog\Model\Product\Visibility;
12+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
13+
use Magento\CatalogGraphQl\DataProvider\Product\SearchCriteriaBuilder;
14+
use Magento\Eav\Model\Config;
15+
use Magento\Framework\Api\Filter;
16+
use Magento\Framework\Api\FilterBuilder;
17+
use Magento\Framework\Api\Search\FilterGroupBuilder;
18+
use Magento\Framework\Api\Search\SearchCriteriaInterface;
19+
use Magento\Framework\Api\SortOrderBuilder;
20+
use Magento\Framework\App\Config\ScopeConfigInterface;
21+
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\Builder;
22+
use PHPUnit\Framework\TestCase;
23+
24+
/**
25+
* Build search criteria
26+
*/
27+
class SearchCriteriaBuilderTest extends TestCase
28+
{
29+
/**
30+
* @var ScopeConfigInterface
31+
*/
32+
private ScopeConfigInterface $scopeConfig;
33+
34+
/**
35+
* @var FilterBuilder
36+
*/
37+
private FilterBuilder $filterBuilder;
38+
39+
/**
40+
* @var FilterGroupBuilder
41+
*/
42+
private FilterGroupBuilder $filterGroupBuilder;
43+
44+
/**
45+
* @var Builder
46+
*/
47+
private Builder $builder;
48+
49+
/**
50+
* @var Visibility
51+
*/
52+
private Visibility $visibility;
53+
54+
/**
55+
* @var SortOrderBuilder
56+
*/
57+
private SortOrderBuilder $sortOrderBuilder;
58+
59+
/**
60+
* @var SearchCriteriaBuilder
61+
*/
62+
private SearchCriteriaBuilder $model;
63+
64+
/**
65+
* @var Config
66+
*/
67+
private Config $eavConfig;
68+
69+
/**
70+
* @inheritdoc
71+
*/
72+
protected function setUp(): void
73+
{
74+
parent::setUp();
75+
$this->builder = $this->createMock(Builder::class);
76+
$this->scopeConfig = $this->createMock(ScopeConfigInterface::class);
77+
$this->filterBuilder = $this->createMock(FilterBuilder::class);
78+
$this->filterGroupBuilder = $this->createMock(FilterGroupBuilder::class);
79+
$this->sortOrderBuilder = $this->createMock(SortOrderBuilder::class);
80+
$this->visibility = $this->createMock(Visibility::class);
81+
$this->eavConfig = $this->createMock(Config::class);
82+
$this->model = new SearchCriteriaBuilder(
83+
$this->builder,
84+
$this->scopeConfig,
85+
$this->filterBuilder,
86+
$this->filterGroupBuilder,
87+
$this->visibility,
88+
$this->sortOrderBuilder,
89+
$this->eavConfig
90+
);
91+
}
92+
93+
public function testBuild(): void
94+
{
95+
$args = ['search' => '', 'pageSize' => 20, 'currentPage' => 1];
96+
97+
$filter = $this->createMock(Filter::class);
98+
99+
$searchCriteria = $this->getMockBuilder(SearchCriteriaInterface::class)
100+
->disableOriginalConstructor()
101+
->getMockForAbstractClass();
102+
$attributeInterface = $this->getMockBuilder(Attribute::class)
103+
->disableOriginalConstructor()
104+
->getMockForAbstractClass();
105+
106+
$attributeInterface->setData(['is_filterable' => 0]);
107+
108+
$this->builder->expects($this->any())
109+
->method('build')
110+
->with('products', $args)
111+
->willReturn($searchCriteria);
112+
$searchCriteria->expects($this->any())->method('getFilterGroups')->willReturn([]);
113+
$this->eavConfig->expects($this->any())
114+
->method('getAttribute')
115+
->with(Product::ENTITY, 'price')
116+
->willReturn($attributeInterface);
117+
118+
$this->sortOrderBuilder->expects($this->once())
119+
->method('setField')
120+
->with('_id')
121+
->willReturnSelf();
122+
$this->sortOrderBuilder->expects($this->once())
123+
->method('setDirection')
124+
->with('DESC')
125+
->willReturnSelf();
126+
$this->sortOrderBuilder->expects($this->any())
127+
->method('create')
128+
->willReturn([]);
129+
130+
$this->filterBuilder->expects($this->once())
131+
->method('setField')
132+
->with('visibility')
133+
->willReturnSelf();
134+
$this->filterBuilder->expects($this->once())
135+
->method('setValue')
136+
->with("")
137+
->willReturnSelf();
138+
$this->filterBuilder->expects($this->once())
139+
->method('setConditionType')
140+
->with('in')
141+
->willReturnSelf();
142+
143+
$this->filterBuilder->expects($this->once())->method('create')->willReturn($filter);
144+
145+
$this->filterGroupBuilder->expects($this->any())
146+
->method('addFilter')
147+
->with($filter)
148+
->willReturnSelf();
149+
150+
$this->model->build($args, true);
151+
}
152+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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\CatalogInventory\Test\Fixture;
9+
10+
use Magento\Framework\DataObject;
11+
use Magento\InventoryApi\Api\Data\SourceItemInterface;
12+
use Magento\InventoryApi\Api\SourceItemsDeleteInterface;
13+
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
14+
use Magento\TestFramework\Fixture\Api\DataMerger;
15+
use Magento\TestFramework\Fixture\Api\ServiceFactory;
16+
use Magento\TestFramework\Fixture\Data\ProcessorInterface;
17+
use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface;
18+
19+
class SourceItem implements RevertibleDataFixtureInterface
20+
{
21+
private const DEFAULT_DATA = [
22+
'sku' => 'SKU-%uniqid%',
23+
'source_code' => 'Source%uniqid%',
24+
'quantity' => 5,
25+
'status' => SourceItemInterface::STATUS_IN_STOCK,
26+
];
27+
28+
/**
29+
* @var ServiceFactory
30+
*/
31+
private ServiceFactory $serviceFactory;
32+
33+
/**
34+
* @var ProcessorInterface
35+
*/
36+
private ProcessorInterface $dataProcessor;
37+
38+
/**
39+
* @var DataMerger
40+
*/
41+
private DataMerger $dataMerger;
42+
43+
/**
44+
* @param ServiceFactory $serviceFactory
45+
* @param ProcessorInterface $dataProcessor
46+
* @param DataMerger $dataMerger
47+
*/
48+
public function __construct(
49+
ServiceFactory $serviceFactory,
50+
ProcessorInterface $dataProcessor,
51+
DataMerger $dataMerger
52+
) {
53+
$this->serviceFactory = $serviceFactory;
54+
$this->dataProcessor = $dataProcessor;
55+
$this->dataMerger = $dataMerger;
56+
}
57+
58+
/**
59+
* @param array $data
60+
* @return DataObject|null
61+
*/
62+
public function apply(array $data = []): ?DataObject
63+
{
64+
$service = $this->serviceFactory->create(SourceItemsSaveInterface::class, 'execute');
65+
66+
return $service->execute(['sourceItems' => [$this->prepareData($data)]]);
67+
}
68+
69+
/**
70+
* @inheritdoc
71+
*/
72+
public function revert(DataObject $data): void
73+
{
74+
$service = $this->serviceFactory->create(SourceItemsDeleteInterface::class, 'execute');
75+
$service->execute(['sourceItems' => [$this->prepareData($data->getData())]]);
76+
}
77+
78+
/**
79+
* Prepare product data
80+
*
81+
* @param array $data
82+
* @return array
83+
*/
84+
private function prepareData(array $data): array
85+
{
86+
$data = $this->dataMerger->merge(self::DEFAULT_DATA, $data, false);
87+
88+
return $this->dataProcessor->process($this, $data);
89+
}
90+
}

app/code/Magento/CatalogUrlRewrite/Model/Products/AdaptUrlRewritesToVisibilityAttribute.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public function execute(array $productIds, int $visibility, int $storeId): void
7979
[
8080
UrlRewrite::ENTITY_ID => $product->getId(),
8181
UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE,
82+
UrlRewrite::STORE_ID => $storeId,
8283
]
8384
);
8485
} elseif ($visibility !== Visibility::VISIBILITY_NOT_VISIBLE) {

app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ public function collectRates(RateRequest $request)
111111
}
112112
} elseif ($item->getProduct()->isVirtual()) {
113113
$request->setPackageValue($request->getPackageValue() - $item->getBaseRowTotal());
114+
$request->setPackageValueWithDiscount(
115+
$request->getPackageValueWithDiscount() - $item->getBaseRowTotal()
116+
);
114117
}
115118
}
116119
}
@@ -133,8 +136,7 @@ public function collectRates(RateRequest $request)
133136
$freeQty += $item->getQty() * ($child->getQty() - $freeShipping);
134137
}
135138
}
136-
} elseif (
137-
($item->getFreeShipping() || $item->getAddress()->getFreeShipping()) &&
139+
} elseif (($item->getFreeShipping() || $item->getAddress()->getFreeShipping()) &&
138140
($item->getFreeShippingMethod() == null || $item->getFreeShippingMethod() &&
139141
$item->getFreeShippingMethod() == 'tablerate_bestway')
140142
) {

app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function collect(
7373
$address->setFreeMethodWeight($data['freeMethodWeight']);
7474

7575
$isFreeShipping = $this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems());
76-
$address->setFreeShipping($isFreeShipping);
76+
$address->setFreeShipping((int)$isFreeShipping);
7777
// recalculate weights
7878
$data = $this->getAssignmentWeightData($address, $shippingAssignment->getItems());
7979
$address->setItemQty($data['addressQty']);

0 commit comments

Comments
 (0)