Skip to content

Commit 808e992

Browse files
committed
Merge branch 'ACP2E-1961' of https://github.com/magento-l3/magento2ce into PR-07032023
2 parents 41883fa + 4c5884a commit 808e992

File tree

4 files changed

+436
-125
lines changed

4 files changed

+436
-125
lines changed

app/code/Magento/Sales/Model/ResourceModel/Report/Bestsellers.php

Lines changed: 185 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,39 @@
55
*/
66
namespace Magento\Sales\Model\ResourceModel\Report;
77

8+
use Magento\Catalog\Model\ResourceModel\Product;
9+
use Magento\Framework\App\ObjectManager;
10+
use Magento\Framework\DB\Select;
11+
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Framework\Model\ResourceModel\Db\Context;
13+
use Magento\Framework\Stdlib\DateTime\DateTime;
14+
use Magento\Framework\Stdlib\DateTime\Timezone\Validator;
15+
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
16+
use Magento\Reports\Model\FlagFactory;
17+
use Magento\Sales\Model\ResourceModel\Helper;
18+
use Magento\Store\Model\Store;
19+
use Magento\Store\Model\StoreManagerInterface;
20+
use Psr\Log\LoggerInterface;
21+
822
/**
923
* Bestsellers report resource model
1024
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1125
*/
1226
class Bestsellers extends AbstractReport
1327
{
14-
const AGGREGATION_DAILY = 'daily';
28+
public const AGGREGATION_DAILY = 'daily';
1529

16-
const AGGREGATION_MONTHLY = 'monthly';
30+
public const AGGREGATION_MONTHLY = 'monthly';
1731

18-
const AGGREGATION_YEARLY = 'yearly';
32+
public const AGGREGATION_YEARLY = 'yearly';
1933

2034
/**
21-
* @var \Magento\Catalog\Model\ResourceModel\Product
35+
* @var Product
2236
*/
2337
protected $_productResource;
2438

2539
/**
26-
* @var \Magento\Sales\Model\ResourceModel\Helper
40+
* @var Helper
2741
*/
2842
protected $_salesResourceHelper;
2943

@@ -37,29 +51,36 @@ class Bestsellers extends AbstractReport
3751
];
3852

3953
/**
40-
* @param \Magento\Framework\Model\ResourceModel\Db\Context $context
41-
* @param \Psr\Log\LoggerInterface $logger
42-
* @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
43-
* @param \Magento\Reports\Model\FlagFactory $reportsFlagFactory
44-
* @param \Magento\Framework\Stdlib\DateTime\Timezone\Validator $timezoneValidator
45-
* @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime
46-
* @param \Magento\Catalog\Model\ResourceModel\Product $productResource
47-
* @param \Magento\Sales\Model\ResourceModel\Helper $salesResourceHelper
54+
* @var StoreManagerInterface
55+
*/
56+
protected $storeManager;
57+
58+
/**
59+
* @param Context $context
60+
* @param LoggerInterface $logger
61+
* @param TimezoneInterface $localeDate
62+
* @param FlagFactory $reportsFlagFactory
63+
* @param Validator $timezoneValidator
64+
* @param DateTime $dateTime
65+
* @param Product $productResource
66+
* @param Helper $salesResourceHelper
67+
* @param string|null $connectionName
4868
* @param array $ignoredProductTypes
49-
* @param string $connectionName
69+
* @param StoreManagerInterface|null $storeManager
5070
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
5171
*/
5272
public function __construct(
53-
\Magento\Framework\Model\ResourceModel\Db\Context $context,
54-
\Psr\Log\LoggerInterface $logger,
55-
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
56-
\Magento\Reports\Model\FlagFactory $reportsFlagFactory,
57-
\Magento\Framework\Stdlib\DateTime\Timezone\Validator $timezoneValidator,
58-
\Magento\Framework\Stdlib\DateTime\DateTime $dateTime,
59-
\Magento\Catalog\Model\ResourceModel\Product $productResource,
60-
\Magento\Sales\Model\ResourceModel\Helper $salesResourceHelper,
61-
$connectionName = null,
62-
array $ignoredProductTypes = []
73+
Context $context,
74+
LoggerInterface $logger,
75+
TimezoneInterface $localeDate,
76+
FlagFactory $reportsFlagFactory,
77+
Validator $timezoneValidator,
78+
DateTime $dateTime,
79+
Product $productResource,
80+
Helper $salesResourceHelper,
81+
?string $connectionName = null,
82+
array $ignoredProductTypes = [],
83+
?StoreManagerInterface $storeManager = null
6384
) {
6485
parent::__construct(
6586
$context,
@@ -73,6 +94,7 @@ public function __construct(
7394
$this->_productResource = $productResource;
7495
$this->_salesResourceHelper = $salesResourceHelper;
7596
$this->ignoredProductTypes = array_merge($this->ignoredProductTypes, $ignoredProductTypes);
97+
$this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class);
7698
}
7799

78100
/**
@@ -92,123 +114,161 @@ protected function _construct()
92114
* @param string|int|\DateTime|array|null $to
93115
* @return $this
94116
* @throws \Exception
95-
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
96117
*/
97118
public function aggregate($from = null, $to = null)
98119
{
99120
$connection = $this->getConnection();
100-
//$this->getConnection()->beginTransaction();
101-
102-
try {
103-
if ($from !== null || $to !== null) {
104-
$subSelect = $this->_getTableDateRangeSelect(
105-
$this->getTable('sales_order'),
106-
'created_at',
107-
'updated_at',
108-
$from,
109-
$to
110-
);
111-
} else {
112-
$subSelect = null;
113-
}
114-
115-
$this->_clearTableByDateRange($this->getMainTable(), $from, $to, $subSelect);
116-
// convert dates to current admin timezone
117-
$periodExpr = $connection->getDatePartSql(
118-
$this->getStoreTZOffsetQuery(
119-
['source_table' => $this->getTable('sales_order')],
120-
'source_table.created_at',
121-
$from,
122-
$to
123-
)
124-
);
125-
$select = $connection->select();
126-
127-
$select->group([$periodExpr, 'source_table.store_id', 'order_item.product_id']);
128-
129-
$columns = [
130-
'period' => $periodExpr,
131-
'store_id' => 'source_table.store_id',
132-
'product_id' => 'order_item.product_id',
133-
'product_name' => new \Zend_Db_Expr('MIN(order_item.name)'),
134-
'product_price' => new \Zend_Db_Expr(
135-
'MIN(IF(order_item_parent.base_price, order_item_parent.base_price, order_item.base_price))' .
136-
'* MIN(source_table.base_to_global_rate)'
137-
),
138-
'qty_ordered' => new \Zend_Db_Expr('SUM(order_item.qty_ordered)'),
139-
];
140-
141-
$select->from(
142-
['source_table' => $this->getTable('sales_order')],
143-
$columns
144-
)->joinInner(
145-
['order_item' => $this->getTable('sales_order_item')],
146-
'order_item.order_id = source_table.entity_id',
147-
[]
148-
)->joinLeft(
149-
['order_item_parent' => $this->getTable('sales_order_item')],
150-
'order_item.parent_item_id = order_item_parent.item_id',
151-
[]
152-
)->where(
153-
'source_table.state != ?',
154-
\Magento\Sales\Model\Order::STATE_CANCELED
155-
)->where(
156-
'order_item.product_type NOT IN(?)',
157-
$this->ignoredProductTypes
158-
);
121+
$this->clearByDateRange($from, $to);
122+
foreach ($this->storeManager->getStores(true) as $store) {
123+
$this->processStoreAggregate($store->getId(), $from, $to);
124+
}
159125

160-
if ($subSelect !== null) {
161-
$select->having($this->_makeConditionFromDateRangeSelect($subSelect, 'period'));
162-
}
163-
164-
$select->useStraightJoin();
165-
// important!
166-
$insertQuery = $select->insertFromSelect($this->getMainTable(), array_keys($columns));
167-
$connection->query($insertQuery);
168-
169-
$columns = [
170-
'period' => 'period',
171-
'store_id' => new \Zend_Db_Expr(\Magento\Store\Model\Store::DEFAULT_STORE_ID),
172-
'product_id' => 'product_id',
173-
'product_name' => new \Zend_Db_Expr('MIN(product_name)'),
174-
'product_price' => new \Zend_Db_Expr('MIN(product_price)'),
175-
'qty_ordered' => new \Zend_Db_Expr('SUM(qty_ordered)'),
176-
];
177-
178-
$select->reset();
179-
$select->from(
180-
$this->getMainTable(),
181-
$columns
182-
)->where(
183-
'store_id <> ?',
184-
\Magento\Store\Model\Store::DEFAULT_STORE_ID
185-
);
126+
$columns = [
127+
'period' => 'period',
128+
'store_id' => new \Zend_Db_Expr(Store::DEFAULT_STORE_ID),
129+
'product_id' => 'product_id',
130+
'product_name' => new \Zend_Db_Expr('MIN(product_name)'),
131+
'product_price' => new \Zend_Db_Expr('MIN(product_price)'),
132+
'qty_ordered' => new \Zend_Db_Expr('SUM(qty_ordered)'),
133+
];
186134

187-
if ($subSelect !== null) {
188-
$select->where($this->_makeConditionFromDateRangeSelect($subSelect, 'period'));
189-
}
190-
191-
$select->group(['period', 'product_id']);
192-
$insertQuery = $select->insertFromSelect($this->getMainTable(), array_keys($columns));
193-
$connection->query($insertQuery);
194-
195-
// update rating
196-
$this->_updateRatingPos(self::AGGREGATION_DAILY);
197-
$this->_updateRatingPos(self::AGGREGATION_MONTHLY);
198-
$this->_updateRatingPos(self::AGGREGATION_YEARLY);
199-
$this->_setFlagData(\Magento\Reports\Model\Flag::REPORT_BESTSELLERS_FLAG_CODE);
200-
} catch (\Exception $e) {
201-
throw $e;
135+
$select = $connection->select();
136+
$select->reset();
137+
$select->from(
138+
$this->getMainTable(),
139+
$columns
140+
)->where(
141+
'store_id <> ?',
142+
Store::DEFAULT_STORE_ID
143+
);
144+
$subSelect = $this->getRangeSubSelect($from, $to);
145+
if ($subSelect !== null) {
146+
$select->where($this->_makeConditionFromDateRangeSelect($subSelect, 'period'));
202147
}
203148

149+
$select->group(['period', 'product_id']);
150+
$insertQuery = $select->insertFromSelect($this->getMainTable(), array_keys($columns));
151+
$connection->query($insertQuery);
152+
153+
$this->_updateRatingPos(self::AGGREGATION_DAILY);
154+
$this->_updateRatingPos(self::AGGREGATION_MONTHLY);
155+
$this->_updateRatingPos(self::AGGREGATION_YEARLY);
156+
$this->_setFlagData(\Magento\Reports\Model\Flag::REPORT_BESTSELLERS_FLAG_CODE);
157+
204158
return $this;
205159
}
206160

161+
/**
162+
* Clear aggregate existing data by range
163+
*
164+
* @param string|int|\DateTime|array|null $from
165+
* @param string|int|\DateTime|array|null $to
166+
* @return void
167+
* @throws LocalizedException
168+
*/
169+
private function clearByDateRange($from = null, $to = null): void
170+
{
171+
$subSelect = $this->getRangeSubSelect($from, $to);
172+
$this->_clearTableByDateRange($this->getMainTable(), $from, $to, $subSelect);
173+
}
174+
175+
/**
176+
* Get report range sub-select
177+
*
178+
* @param string|int|\DateTime|array|null $from
179+
* @param string|int|\DateTime|array|null $to
180+
* @return Select|null
181+
*/
182+
private function getRangeSubSelect($from = null, $to = null): ?Select
183+
{
184+
$subSelect = null;
185+
if ($from !== null || $to !== null) {
186+
$subSelect = $this->_getTableDateRangeSelect(
187+
$this->getTable('sales_order'),
188+
'created_at',
189+
'updated_at',
190+
$from,
191+
$to
192+
);
193+
}
194+
195+
return $subSelect;
196+
}
197+
198+
/**
199+
* Calculate report aggregate per store
200+
*
201+
* @param int|null $storeId
202+
* @param string|int|\DateTime|array|null $from
203+
* @param string|int|\DateTime|array|null $to
204+
* @return void
205+
* @throws LocalizedException
206+
*/
207+
private function processStoreAggregate(?int $storeId, $from = null, $to = null): void
208+
{
209+
$connection = $this->getConnection();
210+
211+
// convert dates to current admin timezone
212+
$periodExpr = $connection->getDatePartSql(
213+
$this->getStoreTZOffsetQuery(
214+
['source_table' => $this->getTable('sales_order')],
215+
'source_table.created_at',
216+
$from,
217+
$to
218+
)
219+
);
220+
$select = $connection->select();
221+
$subSelect = $this->getRangeSubSelect($from, $to);
222+
223+
$select->group([$periodExpr, 'source_table.store_id', 'order_item.product_id']);
224+
225+
$columns = [
226+
'period' => $periodExpr,
227+
'store_id' => 'source_table.store_id',
228+
'product_id' => 'order_item.product_id',
229+
'product_name' => new \Zend_Db_Expr('MIN(order_item.name)'),
230+
'product_price' => new \Zend_Db_Expr(
231+
'MIN(IF(order_item_parent.base_price, order_item_parent.base_price, order_item.base_price))' .
232+
'* MIN(source_table.base_to_global_rate)'
233+
),
234+
'qty_ordered' => new \Zend_Db_Expr('SUM(order_item.qty_ordered)'),
235+
];
236+
237+
$select->from(
238+
['source_table' => $this->getTable('sales_order')],
239+
$columns
240+
)->joinInner(
241+
['order_item' => $this->getTable('sales_order_item')],
242+
'order_item.order_id = source_table.entity_id',
243+
[]
244+
)->joinLeft(
245+
['order_item_parent' => $this->getTable('sales_order_item')],
246+
'order_item.parent_item_id = order_item_parent.item_id',
247+
[]
248+
)->where(
249+
"source_table.entity_id IN (SELECT entity_id FROM " . $this->getTable('sales_order') .
250+
" WHERE store_id = " . $storeId .
251+
" AND state != '" . \Magento\Sales\Model\Order::STATE_CANCELED . "'" .
252+
($subSelect !== null ?
253+
" AND " . $this->_makeConditionFromDateRangeSelect($subSelect, $periodExpr) :
254+
'') . ")"
255+
)->where(
256+
'order_item.product_type NOT IN(?)',
257+
$this->ignoredProductTypes
258+
);
259+
260+
$select->useStraightJoin();
261+
// important!
262+
$insertQuery = $select->insertFromSelect($this->getMainTable(), array_keys($columns));
263+
$connection->query($insertQuery);
264+
}
265+
207266
/**
208267
* Update rating position
209268
*
210269
* @param string $aggregation
211270
* @return $this
271+
* @throws LocalizedException
212272
*/
213273
protected function _updateRatingPos($aggregation)
214274
{

0 commit comments

Comments
 (0)