Skip to content

Commit 8090eb0

Browse files
committed
MC-38074: Report - Products in Carts not following user roles scope
1 parent dd862cd commit 8090eb0

File tree

4 files changed

+195
-27
lines changed

4 files changed

+195
-27
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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\Reports\Model\Product;
9+
10+
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
11+
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
12+
use Magento\Store\Model\StoreManagerInterface;
13+
14+
/**
15+
* Retrieve products data for reports by entity id's
16+
*/
17+
class DataRetriever
18+
{
19+
/**
20+
* @var ProductCollectionFactory
21+
*/
22+
private $productCollectionFactory;
23+
24+
/**
25+
* @var StoreManagerInterface
26+
*/
27+
private $storeManager;
28+
29+
/**
30+
* DataRetriever constructor.
31+
*
32+
* @param ProductCollectionFactory $productCollectionFactory
33+
* @param StoreManagerInterface $storeManager
34+
*/
35+
public function __construct(
36+
ProductCollectionFactory $productCollectionFactory,
37+
StoreManagerInterface $storeManager
38+
) {
39+
$this->productCollectionFactory = $productCollectionFactory;
40+
$this->storeManager = $storeManager;
41+
}
42+
43+
/**
44+
* Retrieve products data by entity id's
45+
*
46+
* @param array $entityIds
47+
* @return array
48+
*/
49+
public function execute(array $entityIds = []): array
50+
{
51+
$productCollection = $this->getProductCollection($entityIds);
52+
53+
return $this->prepareDataByCollection($productCollection);
54+
}
55+
56+
/**
57+
* Get product collection filtered by entity id's
58+
*
59+
* @param array $entityIds
60+
* @return ProductCollection
61+
*/
62+
private function getProductCollection(array $entityIds = []): ProductCollection
63+
{
64+
$productCollection = $this->productCollectionFactory->create();
65+
$productCollection->addAttributeToSelect('name');
66+
$productCollection->addIdFilter($entityIds);
67+
$productCollection->addPriceData(null, $this->getWebsiteIdForFilter());
68+
69+
return $productCollection;
70+
}
71+
72+
/**
73+
* Retrieve website id for filter collection
74+
*
75+
* @return int
76+
*/
77+
private function getWebsiteIdForFilter(): int
78+
{
79+
$defaultStoreView = $this->storeManager->getDefaultStoreView();
80+
if ($defaultStoreView) {
81+
$websiteId = (int)$defaultStoreView->getWebsiteId();
82+
} else {
83+
$websites = $this->storeManager->getWebsites();
84+
$website = reset($websites);
85+
$websiteId = (int)$website->getId();
86+
}
87+
88+
return $websiteId;
89+
}
90+
91+
/**
92+
* Prepare data by collection
93+
*
94+
* @param ProductCollection $productCollection
95+
* @return array
96+
*/
97+
private function prepareDataByCollection(ProductCollection $productCollection): array
98+
{
99+
$productsData = [];
100+
foreach ($productCollection as $product) {
101+
$productsData[$product->getId()] = $product->getData();
102+
}
103+
104+
return $productsData;
105+
}
106+
}

app/code/Magento/Reports/Model/ResourceModel/Quote/Item/Collection.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
namespace Magento\Reports\Model\ResourceModel\Quote\Item;
99

10-
use Magento\Framework\App\ResourceConnection;
10+
use Magento\Framework\App\ObjectManager;
11+
use Magento\Reports\Model\Product\DataRetriever as ProductDataRetriever;
1112

1213
/**
1314
* Collection of Magento\Quote\Model\Quote\Item
@@ -49,6 +50,11 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
4950
*/
5051
protected $orderResource;
5152

53+
/**
54+
* @var ProductDataRetriever
55+
*/
56+
private $productDataRetriever;
57+
5258
/**
5359
* @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
5460
* @param \Psr\Log\LoggerInterface $logger
@@ -59,6 +65,9 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
5965
* @param \Magento\Sales\Model\ResourceModel\Order\Collection $orderResource
6066
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
6167
* @param \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource
68+
* @param ProductDataRetriever|null $productDataRetriever
69+
*
70+
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
6271
*/
6372
public function __construct(
6473
\Magento\Framework\Data\Collection\EntityFactory $entityFactory,
@@ -69,7 +78,8 @@ public function __construct(
6978
\Magento\Customer\Model\ResourceModel\Customer $customerResource,
7079
\Magento\Sales\Model\ResourceModel\Order\Collection $orderResource,
7180
\Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
72-
\Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null
81+
\Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null,
82+
?ProductDataRetriever $productDataRetriever = null
7383
) {
7484
parent::__construct(
7585
$entityFactory,
@@ -82,6 +92,8 @@ public function __construct(
8292
$this->productResource = $productResource;
8393
$this->customerResource = $customerResource;
8494
$this->orderResource = $orderResource;
95+
$this->productDataRetriever = $productDataRetriever
96+
?? ObjectManager::getInstance()->get(ProductDataRetriever::class);
8597
}
8698

8799
/**
@@ -225,7 +237,7 @@ protected function _afterLoad()
225237
foreach ($items as $item) {
226238
$productIds[] = $item->getProductId();
227239
}
228-
$productData = $this->getProductData($productIds);
240+
$productData = $this->productDataRetriever->execute($productIds);
229241
$orderData = $this->getOrdersData($productIds);
230242
foreach ($items as $item) {
231243
$item->setId($item->getProductId());

app/code/Magento/Reports/Test/Unit/Model/ResourceModel/Report/Quote/CollectionTest.php

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77

88
namespace Magento\Reports\Test\Unit\Model\ResourceModel\Report\Quote;
99

10-
use Magento\Eav\Model\Entity\AbstractEntity;
10+
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
1111
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
12-
use Magento\Framework\DB\Adapter\AdapterInterface;
1312
use Magento\Framework\DB\Adapter\Pdo\Mysql;
1413
use Magento\Framework\DB\Select;
1514
use Magento\Framework\Event\ManagerInterface;
1615
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
1716
use Magento\Quote\Model\ResourceModel\Quote;
18-
use Magento\Reports\Model\ResourceModel\Quote\Collection;
17+
use Magento\Reports\Model\Product\DataRetriever as ProductDataRetriever;
18+
use Magento\Reports\Model\ResourceModel\Quote\Collection as QuoteCollection;
19+
use Magento\Reports\Model\ResourceModel\Quote\Item\Collection as QuoteItemCollection;
20+
use Magento\Sales\Model\ResourceModel\Order\Collection as OrderCollection;
1921
use PHPUnit\Framework\MockObject\MockObject;
2022
use PHPUnit\Framework\TestCase;
2123

@@ -34,16 +36,22 @@ class CollectionTest extends TestCase
3436
*/
3537
protected $selectMock;
3638

39+
/**
40+
* @var ProductDataRetriever|MockObject
41+
*/
42+
private $productDataRetriever;
43+
3744
protected function setUp(): void
3845
{
3946
$this->objectManager = new ObjectManager($this);
4047
$this->selectMock = $this->createMock(Select::class);
48+
$this->productDataRetriever = $this->createMock(ProductDataRetriever::class);
4149
}
4250

4351
public function testGetSelectCountSql()
4452
{
4553
/** @var MockObject $collection */
46-
$collection = $this->getMockBuilder(Collection::class)
54+
$collection = $this->getMockBuilder(QuoteCollection::class)
4755
->setMethods(['getSelect'])
4856
->disableOriginalConstructor()
4957
->getMock();
@@ -61,8 +69,8 @@ public function testPrepareActiveCartItems()
6169
{
6270
/** @var MockObject $collection */
6371
$constructArgs = $this->objectManager
64-
->getConstructArguments(\Magento\Reports\Model\ResourceModel\Quote\Item\Collection::class);
65-
$collection = $this->getMockBuilder(\Magento\Reports\Model\ResourceModel\Quote\Item\Collection::class)
72+
->getConstructArguments(QuoteItemCollection::class);
73+
$collection = $this->getMockBuilder(QuoteItemCollection::class)
6674
->setMethods(['getSelect', 'getTable', 'getFlag', 'setFlag'])
6775
->disableOriginalConstructor()
6876
->setConstructorArgs($constructArgs)
@@ -88,18 +96,18 @@ public function testLoadWithFilter()
8896
{
8997
/** @var MockObject $collection */
9098
$constructArgs = $this->objectManager
91-
->getConstructArguments(\Magento\Reports\Model\ResourceModel\Quote\Item\Collection::class);
99+
->getConstructArguments(QuoteItemCollection::class);
92100
$constructArgs['eventManager'] = $this->getMockForAbstractClass(ManagerInterface::class);
93-
$connectionMock = $this->getMockForAbstractClass(AdapterInterface::class);
94101
$resourceMock = $this->createMock(Quote::class);
95102
$resourceMock->expects($this->any())->method('getConnection')
96103
->willReturn($this->createMock(Mysql::class));
97104
$constructArgs['resource'] = $resourceMock;
98-
$productResourceMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product\Collection::class);
105+
$productResourceMock = $this->createMock(ProductCollection::class);
99106
$constructArgs['productResource'] = $productResourceMock;
100-
$orderResourceMock = $this->createMock(\Magento\Sales\Model\ResourceModel\Order\Collection::class);
107+
$orderResourceMock = $this->createMock(OrderCollection::class);
101108
$constructArgs['orderResource'] = $orderResourceMock;
102-
$collection = $this->getMockBuilder(\Magento\Reports\Model\ResourceModel\Quote\Item\Collection::class)
109+
$constructArgs['productDataRetriever'] = $this->productDataRetriever;
110+
$collection = $this->getMockBuilder(QuoteItemCollection::class)
103111
->setMethods(
104112
[
105113
'_beforeLoad',
@@ -129,24 +137,12 @@ public function testLoadWithFilter()
129137
//productLoad()
130138
$productAttributeMock = $this->createMock(AbstractAttribute::class);
131139
$priceAttributeMock = $this->createMock(AbstractAttribute::class);
132-
$productResourceMock->expects($this->once())->method('getConnection')->willReturn($connectionMock);
133140
$productResourceMock->expects($this->any())->method('getAttribute')
134141
->willReturnMap([['name', $productAttributeMock], ['price', $priceAttributeMock]]);
135-
$productResourceMock->expects($this->once())->method('getSelect')->willReturn($this->selectMock);
136-
$eavEntity = $this->createMock(AbstractEntity::class);
137-
$eavEntity->expects($this->once())->method('getLinkField')->willReturn('entity_id');
138-
$productResourceMock->expects($this->once())->method('getEntity')->willReturn($eavEntity);
139-
$this->selectMock->expects($this->once())->method('reset')->willReturnSelf();
140-
$this->selectMock->expects($this->once())->method('from')->willReturnSelf();
141-
$this->selectMock->expects($this->once())->method('useStraightJoin')->willReturnSelf();
142-
$this->selectMock->expects($this->once())->method('joinInner')->willReturnSelf();
143-
$this->selectMock->expects($this->once())->method('joinLeft')->willReturnSelf();
144142
$collection->expects($this->once())->method('getOrdersData')->willReturn([]);
145-
$productAttributeMock->expects($this->once())->method('getBackend')->willReturnSelf();
146-
$priceAttributeMock->expects($this->once())->method('getBackend')->willReturnSelf();
147-
$connectionMock->expects($this->once())->method('fetchAssoc')->willReturn([1, 2, 3]);
148143
//_afterLoad()
149144
$collection->expects($this->once())->method('getItems')->willReturn([]);
145+
$this->productDataRetriever->expects($this->once())->method('execute')->willReturn([]);
150146
$collection->loadWithFilter();
151147
}
152148
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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\Reports\Model\Product;
9+
10+
use Magento\Catalog\Model\Indexer\Product\Price\Processor;
11+
use Magento\TestFramework\Helper\Bootstrap;
12+
use PHPUnit\Framework\TestCase;
13+
14+
/**
15+
* @magentoAppArea adminhtml
16+
*/
17+
class DataRetrieverTest extends TestCase
18+
{
19+
/**
20+
* @var DataRetriever
21+
*/
22+
private $dataRetriever;
23+
24+
/**
25+
* @var Processor
26+
*/
27+
private $priceIndexerProcessor;
28+
29+
protected function setUp(): void
30+
{
31+
$this->dataRetriever = Bootstrap::getObjectManager()->create(DataRetriever::class);
32+
$this->priceIndexerProcessor = Bootstrap::getObjectManager()->get(Processor::class);
33+
}
34+
35+
/**
36+
* Test retrieve products data for reports by entity id's
37+
* Do not use magentoDbIsolation because index statement changing "tears" transaction (triggers creating)
38+
*
39+
* @magentoDataFixture Magento/Catalog/_files/product_simple.php
40+
* @magentoConfigFixture default/reports/options/enabled 1
41+
* @magentoDbIsolation disabled
42+
*
43+
* @return void
44+
*/
45+
public function testExecute(): void
46+
{
47+
$productId = 1;
48+
$this->priceIndexerProcessor->reindexAll();
49+
$actualResult = $this->dataRetriever->execute([$productId]);
50+
$this->assertNotEmpty($actualResult);
51+
$this->assertCount(1, $actualResult);
52+
$this->assertEquals(10, $actualResult[$productId]['price']);
53+
}
54+
}

0 commit comments

Comments
 (0)