5
5
*/
6
6
namespace Magento \Sales \Model \ResourceModel \Report ;
7
7
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
+
8
22
/**
9
23
* Bestsellers report resource model
10
24
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
11
25
*/
12
26
class Bestsellers extends AbstractReport
13
27
{
14
- const AGGREGATION_DAILY = 'daily ' ;
28
+ public const AGGREGATION_DAILY = 'daily ' ;
15
29
16
- const AGGREGATION_MONTHLY = 'monthly ' ;
30
+ public const AGGREGATION_MONTHLY = 'monthly ' ;
17
31
18
- const AGGREGATION_YEARLY = 'yearly ' ;
32
+ public const AGGREGATION_YEARLY = 'yearly ' ;
19
33
20
34
/**
21
- * @var \Magento\Catalog\Model\ResourceModel\ Product
35
+ * @var Product
22
36
*/
23
37
protected $ _productResource ;
24
38
25
39
/**
26
- * @var \Magento\Sales\Model\ResourceModel\ Helper
40
+ * @var Helper
27
41
*/
28
42
protected $ _salesResourceHelper ;
29
43
@@ -37,29 +51,36 @@ class Bestsellers extends AbstractReport
37
51
];
38
52
39
53
/**
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
48
68
* @param array $ignoredProductTypes
49
- * @param string $connectionName
69
+ * @param StoreManagerInterface|null $storeManager
50
70
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
51
71
*/
52
72
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
63
84
) {
64
85
parent ::__construct (
65
86
$ context ,
@@ -73,6 +94,7 @@ public function __construct(
73
94
$ this ->_productResource = $ productResource ;
74
95
$ this ->_salesResourceHelper = $ salesResourceHelper ;
75
96
$ this ->ignoredProductTypes = array_merge ($ this ->ignoredProductTypes , $ ignoredProductTypes );
97
+ $ this ->storeManager = $ storeManager ?: ObjectManager::getInstance ()->get (StoreManagerInterface::class);
76
98
}
77
99
78
100
/**
@@ -92,123 +114,162 @@ protected function _construct()
92
114
* @param string|int|\DateTime|array|null $to
93
115
* @return $this
94
116
* @throws \Exception
95
- * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
96
117
*/
97
118
public function aggregate ($ from = null , $ to = null )
98
119
{
99
120
$ 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 );
159
122
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
- );
123
+ foreach ($ this ->storeManager ->getStores (true ) as $ store ) {
124
+ $ this ->processStoreAggregate ($ store ->getId (), $ from , $ to );
125
+ }
126
+
127
+ $ columns = [
128
+ 'period ' => 'period ' ,
129
+ 'store_id ' => new \Zend_Db_Expr (Store::DEFAULT_STORE_ID ),
130
+ 'product_id ' => 'product_id ' ,
131
+ 'product_name ' => new \Zend_Db_Expr ('MIN(product_name) ' ),
132
+ 'product_price ' => new \Zend_Db_Expr ('MIN(product_price) ' ),
133
+ 'qty_ordered ' => new \Zend_Db_Expr ('SUM(qty_ordered) ' ),
134
+ ];
186
135
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 ;
136
+ $ select = $ connection ->select ();
137
+ $ select ->reset ();
138
+ $ select ->from (
139
+ $ this ->getMainTable (),
140
+ $ columns
141
+ )->where (
142
+ 'store_id <> ? ' ,
143
+ Store::DEFAULT_STORE_ID
144
+ );
145
+ $ subSelect = $ this ->getRangeSubSelect ($ from , $ to );
146
+ if ($ subSelect !== null ) {
147
+ $ select ->where ($ this ->_makeConditionFromDateRangeSelect ($ subSelect , 'period ' ));
202
148
}
203
149
150
+ $ select ->group (['period ' , 'product_id ' ]);
151
+ $ insertQuery = $ select ->insertFromSelect ($ this ->getMainTable (), array_keys ($ columns ));
152
+ $ connection ->query ($ insertQuery );
153
+
154
+ $ this ->_updateRatingPos (self ::AGGREGATION_DAILY );
155
+ $ this ->_updateRatingPos (self ::AGGREGATION_MONTHLY );
156
+ $ this ->_updateRatingPos (self ::AGGREGATION_YEARLY );
157
+ $ this ->_setFlagData (\Magento \Reports \Model \Flag::REPORT_BESTSELLERS_FLAG_CODE );
158
+
204
159
return $ this ;
205
160
}
206
161
162
+ /**
163
+ * Clear aggregate existing data by range
164
+ *
165
+ * @param string|int|\DateTime|array|null $from
166
+ * @param string|int|\DateTime|array|null $to
167
+ * @return void
168
+ * @throws LocalizedException
169
+ */
170
+ protected function clearByDateRange ($ from = null , $ to = null ): void
171
+ {
172
+ $ subSelect = $ this ->getRangeSubSelect ($ from , $ to );
173
+ $ this ->_clearTableByDateRange ($ this ->getMainTable (), $ from , $ to , $ subSelect );
174
+ }
175
+
176
+ /**
177
+ * Get report range sub-select
178
+ *
179
+ * @param string|int|\DateTime|array|null $from
180
+ * @param string|int|\DateTime|array|null $to
181
+ * @return Select|null
182
+ */
183
+ protected function getRangeSubSelect ($ from = null , $ to = null ): ?Select
184
+ {
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
+ } else {
194
+ $ subSelect = null ;
195
+ }
196
+
197
+ return $ subSelect ;
198
+ }
199
+
200
+ /**
201
+ * Calculate report aggregate per store
202
+ *
203
+ * @param int $storeId
204
+ * @param string|int|\DateTime|array|null $from
205
+ * @param string|int|\DateTime|array|null $to
206
+ * @return void
207
+ * @throws LocalizedException
208
+ */
209
+ protected function processStoreAggregate (int $ storeId , $ from = null , $ to = null ): void
210
+ {
211
+ $ connection = $ this ->getConnection ();
212
+
213
+ // convert dates to current admin timezone
214
+ $ periodExpr = $ connection ->getDatePartSql (
215
+ $ this ->getStoreTZOffsetQuery (
216
+ ['source_table ' => $ this ->getTable ('sales_order ' )],
217
+ 'source_table.created_at ' ,
218
+ $ from ,
219
+ $ to
220
+ )
221
+ );
222
+ $ select = $ connection ->select ();
223
+ $ subSelect = $ this ->getRangeSubSelect ($ from , $ to );
224
+
225
+ $ select ->group ([$ periodExpr , 'source_table.store_id ' , 'order_item.product_id ' ]);
226
+
227
+ $ columns = [
228
+ 'period ' => $ periodExpr ,
229
+ 'store_id ' => 'source_table.store_id ' ,
230
+ 'product_id ' => 'order_item.product_id ' ,
231
+ 'product_name ' => new \Zend_Db_Expr ('MIN(order_item.name) ' ),
232
+ 'product_price ' => new \Zend_Db_Expr (
233
+ 'MIN(IF(order_item_parent.base_price, order_item_parent.base_price, order_item.base_price)) ' .
234
+ '* MIN(source_table.base_to_global_rate) '
235
+ ),
236
+ 'qty_ordered ' => new \Zend_Db_Expr ('SUM(order_item.qty_ordered) ' ),
237
+ ];
238
+
239
+ $ select ->from (
240
+ ['source_table ' => $ this ->getTable ('sales_order ' )],
241
+ $ columns
242
+ )->joinInner (
243
+ ['order_item ' => $ this ->getTable ('sales_order_item ' )],
244
+ 'order_item.order_id = source_table.entity_id ' ,
245
+ []
246
+ )->joinLeft (
247
+ ['order_item_parent ' => $ this ->getTable ('sales_order_item ' )],
248
+ 'order_item.parent_item_id = order_item_parent.item_id ' ,
249
+ []
250
+ )->where (
251
+ 'source_table.entity_id IN (?) ' ,
252
+ "SELECT entity_id FROM " . $ this ->getTable ('sales_order ' ) .
253
+ " WHERE store_id = " . $ storeId .
254
+ " AND state != ' " . \Magento \Sales \Model \Order::STATE_CANCELED . "' " .
255
+ ($ subSelect !== null ? " AND " . $ this ->_makeConditionFromDateRangeSelect ($ subSelect , $ periodExpr ) : '' )
256
+ )->where (
257
+ 'order_item.product_type NOT IN(?) ' ,
258
+ $ this ->ignoredProductTypes
259
+ );
260
+
261
+ $ select ->useStraightJoin ();
262
+ // important!
263
+ $ insertQuery = $ select ->insertFromSelect ($ this ->getMainTable (), array_keys ($ columns ));
264
+ $ connection ->query ($ insertQuery );
265
+ }
266
+
207
267
/**
208
268
* Update rating position
209
269
*
210
270
* @param string $aggregation
211
271
* @return $this
272
+ * @throws LocalizedException
212
273
*/
213
274
protected function _updateRatingPos ($ aggregation )
214
275
{
0 commit comments