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,161 @@ 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 );
122
+ foreach ($ this ->storeManager ->getStores (true ) as $ store ) {
123
+ $ this ->processStoreAggregate ($ store ->getId (), $ from , $ to );
124
+ }
159
125
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
+ ];
186
134
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 ' ));
202
147
}
203
148
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
+
204
158
return $ this ;
205
159
}
206
160
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
+
207
266
/**
208
267
* Update rating position
209
268
*
210
269
* @param string $aggregation
211
270
* @return $this
271
+ * @throws LocalizedException
212
272
*/
213
273
protected function _updateRatingPos ($ aggregation )
214
274
{
0 commit comments