Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
basehandler.php
1<?php
2
4
24
25abstract class BaseHandler extends BaseReport implements IReportMultipleData
26{
27 protected const MAX_CHART_COLUMNS_COUNT = 5;
28 protected const MAX_STORES_LIST_CHARS = 25;
29
30 abstract public function prepare();
31
32 public function getMultipleData()
33 {
34 return $this->getCalculatedData();
35 }
36
37 public function getMultipleDemoData()
38 {
39 return [];
40 }
41
42 protected function getStoreTotals(): array
43 {
44 $storeTotals = $this->getStoreProductData();
45 if (!empty($storeTotals))
46 {
47 $receivedQuantities = $this->getReceivedQuantity();
48 $soldAmounts = $this->getSoldAmounts();
49 $outgoingQuantities = $this->getOutgoingQuantity();
50 $receivedQuantitiesDifference = $this->getReceivedQuantityForDifference();
51 $outgoingQuantitiesDifference = $this->getOutgoingQuantityForDifference();
52 $soldAmountsDifference = $this->getSoldAmountsForDifference();
53
54 $groupedStoreTotals = [];
55 foreach ($storeTotals as $key => $storeTotal)
56 {
57 $storeId = (int)$storeTotal['TMP_STORE_ID'];
58 $measureId = (int)$storeTotal['MEASURE_ID'] ?: \CCatalogMeasure::getDefaultMeasure(true)['ID'];
59 if (isset($groupedStoreTotals[$storeId][$measureId]))
60 {
61 $groupedStoreTotals[$storeId][$measureId]['AMOUNT_SUM'] += (float)$storeTotal['AMOUNT_SUM'];
62 $groupedStoreTotals[$storeId][$measureId]['QUANTITY_RESERVED_SUM'] += (float)$storeTotal['QUANTITY_RESERVED_SUM'];
63
64 continue;
65 }
66
67 $groupedStoreTotals[$storeId][$measureId] = [
68 'TITLE' => $storeTotal['TITLE'],
69 'TMP_STORE_ID' => $storeId,
70 'SORT' => $storeTotal['SORT'],
71 'AMOUNT_SUM' => (float)$storeTotal['AMOUNT_SUM'],
72 'QUANTITY_RESERVED_SUM' => (float)$storeTotal['QUANTITY_RESERVED_SUM'],
73 'MEASURE_ID' => $measureId,
74 ];
75
76 if (array_key_exists($storeId, $receivedQuantities))
77 {
78 $groupedStoreTotals[$storeId][$measureId]['RECEIVED_QUANTITIES'] = $receivedQuantities[$storeId];
79 }
80 if (array_key_exists($storeId, $receivedQuantitiesDifference))
81 {
82 $groupedStoreTotals[$storeId][$measureId]['RECEIVED_QUANTITIES_DIFFERENCE'] = $receivedQuantitiesDifference[$storeId];
83 }
84
85 if (array_key_exists($storeId, $outgoingQuantities))
86 {
87 $groupedStoreTotals[$storeId][$measureId]['OUTGOING_QUANTITIES'] = $outgoingQuantities[$storeId];
88 }
89 if (array_key_exists($storeId, $outgoingQuantitiesDifference))
90 {
91 $groupedStoreTotals[$storeId][$measureId]['OUTGOING_QUANTITIES_DIFFERENCE'] = $outgoingQuantitiesDifference[$storeId];
92 }
93
94 if (array_key_exists($storeId, $soldAmounts))
95 {
96 $groupedStoreTotals[$storeId][$measureId]['SOLD_AMOUNTS'] = $soldAmounts[$storeId];
97 }
98 if (array_key_exists($storeId, $soldAmountsDifference))
99 {
100 $groupedStoreTotals[$storeId][$measureId]['SOLD_AMOUNTS_DIFFERENCE'] = $soldAmountsDifference[$storeId];
101 }
102
103 ksort($groupedStoreTotals[$storeId]);
104 }
105 ksort($groupedStoreTotals);
106
107 $storeTotals = $this->prepareStoreTotals($groupedStoreTotals);
108 }
109
110 return $storeTotals;
111 }
112
113 protected static function formChartSliderUrl(string $componentName, array $filter): string
114 {
115 $sliderUrl = \CComponentEngine::makeComponentPath($componentName);
116 $sliderUrl = getLocalPath('components'.$sliderUrl.'/slider.php');
117
118 $uri = new Uri($sliderUrl);
119
120 if (isset($filter['STORES']))
121 {
122 $uri->addParams(['storeIds' => $filter['STORES']]);
123 }
124 if (isset($filter['PRODUCTS']))
125 {
126 $uri->addParams(['productIds' => $filter['PRODUCTS']]);
127 }
128 if (isset($filter['REPORT_INTERVAL']))
129 {
130 $uri->addParams([
131 'reportFrom' => $filter['REPORT_INTERVAL']['FROM'],
132 'reportTo' => $filter['REPORT_INTERVAL']['TO'],
133 ]);
134 }
135 else
136 {
137 $defaultInterval = StoreStockSale::getDefaultReportInterval();
138 $uri->addParams([
139 'reportFrom' => $defaultInterval['FROM'],
140 'reportTo' => $defaultInterval['TO'],
141 ]);
142 }
143
144 return $uri->getUri();
145 }
146
147 private function getStoreProductData(): array
148 {
149 $accessController = AccessController::getCurrent();
150 if (!$accessController->check(ActionDictionary::ACTION_STORE_VIEW))
151 {
152 return [];
153 }
154
155 // adding a new runtime reference field with right join
156 // in order to select all the stores and not just the
157 // ones that have corresponding entries in b_catalog_store_product
158 $queryParams = [
159 'select' => [
160 'TITLE' => 'STORE_TMP.TITLE',
161 'TMP_STORE_ID' => 'STORE_TMP.ID',
162 'SORT' => 'STORE_TMP.SORT',
163 'AMOUNT_SUM',
164 'QUANTITY_RESERVED_SUM',
165 'MEASURE_ID' => 'PRODUCT.MEASURE',
166 ],
167 'filter' => [
168 '=STORE_TMP.ACTIVE' => 'Y',
169 ],
170 'group' => ['TMP_STORE_ID', 'MEASURE_ID'],
171 'order' => ['SORT'],
172 'runtime' => [
173 new ExpressionField('AMOUNT_SUM', 'SUM(AMOUNT)'),
174 new ExpressionField('QUANTITY_RESERVED_SUM', 'SUM(%s)', ['QUANTITY_RESERVED']),
175 (new Reference(
176 'STORE_TMP',
177 StoreTable::class,
178 Join::on('this.STORE_ID', 'ref.ID')
179 ))->configureJoinType(Join::TYPE_RIGHT),
180 ],
181 ];
182
183 $userFilterParameters = $this->getFilterParameters();
184
185 if (isset($userFilterParameters['STORES']) && is_array($userFilterParameters['STORES']))
186 {
187 $storesList = $userFilterParameters['STORES'];
188 }
189 else
190 {
191 $storesList = null;
192 }
193
194 $filteredStoresList = self::getFilteredByRightsStoreList($storesList);
195
196 if (is_array($filteredStoresList))
197 {
198 $queryParams['filter']['=TMP_STORE_ID'] = $filteredStoresList;
199 }
200
201 if (!empty($userFilterParameters['PRODUCTS']) && is_array($userFilterParameters['PRODUCTS']))
202 {
203 $queryParams['filter'][] = $this->getProductFilter($userFilterParameters['PRODUCTS']);
204 }
205
206 return StoreProductTable::getList($queryParams)->fetchAll();
207 }
208
209 protected function getProductFilter(array $productFilter): array
210 {
211 return [
212 '=PRODUCT_ID' => StoreStockFilter::prepareProductFilter($productFilter),
213 [
214 'LOGIC' => 'OR',
215 '!=AMOUNT' => 0,
216 '!=QUANTITY_RESERVED' => 0,
217 ],
218 ];
219 }
220
221 private function prepareStoreTotals(array $storeTotals): array
222 {
223 $preparedTotals = [];
224
225 foreach ($storeTotals as $storeId => $storeTotal)
226 {
227 foreach ($storeTotal as $measureId => $entry)
228 {
229 if (!isset($preparedTotals[$storeId]))
230 {
231 $preparedTotals[$storeId] = [
232 'TITLE' => $entry['TITLE'],
233 'STORE_ID' => $storeId,
234 'TOTALS' => [],
235 ];
236 }
237
238 $soldAmountDifferenceData = $entry['SOLD_AMOUNTS_DIFFERENCE'] ?? [];
239 $receivedQuantitiesDifferenceData = $entry['RECEIVED_QUANTITIES_DIFFERENCE'] ?? [];
240 $outgoingQuantitiesDifferenceData = $entry['OUTGOING_QUANTITIES_DIFFERENCE'] ?? [];
241 $amountSum =
242 (float)$entry['AMOUNT_SUM']
243 - ($receivedQuantitiesDifferenceData[$measureId] ?? 0.0)
244 + ($outgoingQuantitiesDifferenceData[$measureId] ?? 0.0)
245 + ($soldAmountDifferenceData[$measureId] ?? 0.0)
246 ;
247 $quantityReservedSum = (float)$entry['QUANTITY_RESERVED_SUM'];
248
249 $quantity = $amountSum - $quantityReservedSum;
250 $productsSoldAmount = $entry['SOLD_AMOUNTS'] ?? [];
251 $receivedQuantityData = $entry['RECEIVED_QUANTITIES'] ?? [];
252 $outgoingQuantityData = $entry['OUTGOING_QUANTITIES'] ?? [];
253
254 $startingQuantity =
255 $amountSum
256 - ($receivedQuantityData[$measureId] ?? 0.0)
257 + ($outgoingQuantityData[$measureId] ?? 0.0)
258 + ($productsSoldAmount[$measureId] ?? 0.0)
259 ;
260 $receivedQuantity = ($receivedQuantityData[$measureId] ?? 0.0);
261 $amountSold = $productsSoldAmount[$measureId] ?? 0.0;
262
263 $isStoreEmpty = true;
264 $values = [
265 $startingQuantity, $receivedQuantity, $amountSum, $quantityReservedSum, $quantity, $amountSold,
266 ];
267 foreach ($values as $value)
268 {
269 if ($value !== 0.0)
270 {
271 $isStoreEmpty = false;
272 break;
273 }
274 }
275 if ($isStoreEmpty)
276 {
277 continue;
278 }
279
280 if (!isset($preparedTotals[$storeId]['TOTALS'][$measureId]))
281 {
282 $preparedTotals[$storeId]['TOTALS'][$measureId] = [
283 'STARTING_QUANTITY' => 0,
284 'RECEIVED_QUANTITY' => 0,
285 'AMOUNT_SUM' => 0,
286 'QUANTITY_RESERVED_SUM' => 0,
287 'QUANTITY' => 0,
288 'AMOUNT_SOLD' => 0,
289 ];
290 }
291
292 $preparedTotals[$storeId]['TOTALS'][$measureId]['STARTING_QUANTITY'] += $startingQuantity;
293 $preparedTotals[$storeId]['TOTALS'][$measureId]['RECEIVED_QUANTITY'] += $receivedQuantity;
294 $preparedTotals[$storeId]['TOTALS'][$measureId]['AMOUNT_SUM'] += $amountSum;
295 $preparedTotals[$storeId]['TOTALS'][$measureId]['QUANTITY_RESERVED_SUM'] += $quantityReservedSum;
296 $preparedTotals[$storeId]['TOTALS'][$measureId]['QUANTITY'] += $quantity;
297 $preparedTotals[$storeId]['TOTALS'][$measureId]['AMOUNT_SOLD'] += $amountSold;
298 }
299 }
300
301 return $preparedTotals;
302 }
303
304 private function getFormattedFilterForDifference(): ?array
305 {
306 $formattedFilter = $this->getFormattedFilter();
307 $differenceFilter = $formattedFilter;
308 $currentTime = new DateTime();
309 $filterTimeTo = new DateTime($differenceFilter['REPORT_INTERVAL']['TO']);
310 if ($currentTime > $filterTimeTo)
311 {
312 $differenceFilter['REPORT_INTERVAL']['FROM'] = $differenceFilter['REPORT_INTERVAL']['TO'];
313 \CTimeZone::Disable();
314 $differenceFilter['REPORT_INTERVAL']['TO'] = $currentTime->toString();
315 \CTimeZone::Enable();
316 }
317 else
318 {
319 return null;
320 }
321
322 return $differenceFilter;
323 }
324
325 private function getReceivedQuantityForDifference(): array
326 {
327 $formattedFilterForDifference = $this->getFormattedFilterForDifference();
328 if (!$formattedFilterForDifference)
329 {
330 return [];
331 }
332
333 return StoreStockQuantity::getReceivedQuantityForStores($formattedFilterForDifference);
334 }
335
336 private function getOutgoingQuantityForDifference(): array
337 {
338 $formattedFilterForDifference = $this->getFormattedFilterForDifference();
339 if (!$formattedFilterForDifference)
340 {
341 return [];
342 }
343
344 return StoreStockQuantity::getOutgoingQuantityForStores($formattedFilterForDifference);
345 }
346
347 private function getSoldAmountsForDifference(): array
348 {
349 $formattedFilterForDifference = $this->getFormattedFilterForDifference();
350 if (!$formattedFilterForDifference)
351 {
352 return [];
353 }
354
355 return StoreStockSale::getProductsSoldAmountForStores($formattedFilterForDifference);
356 }
357
358 private function getReceivedQuantity(): array
359 {
360 $receivedQuantityFilter = $this->getFormattedFilter();
361
362 return StoreStockQuantity::getReceivedQuantityForStores($receivedQuantityFilter);
363 }
364
365 private function getOutgoingQuantity(): array
366 {
367 $outgoingQuantityFilter = $this->getFormattedFilter();
368
369 return StoreStockQuantity::getOutgoingQuantityForStores($outgoingQuantityFilter);
370 }
371
372 private function getSoldAmounts(): array
373 {
374 $filter = $this->getFormattedFilter();
375
377 }
378
382 protected function getFormattedFilter(): array
383 {
384 $filter = $this->getFilterParameters();
385
386 $formattedFilter = [];
387
388 $storesList = (isset($filter['STORES']) && is_array($filter['STORES'])) ? $filter['STORES'] : null;
389 $filteredStoresList = self::getFilteredByRightsStoreList($storesList);
390
391 if (is_array($filteredStoresList))
392 {
393 $formattedFilter['STORES'] = $filteredStoresList;
394 }
395
396 if (!empty($filter['PRODUCTS']))
397 {
398 $formattedFilter['PRODUCTS'] = StoreStockFilter::prepareProductFilter($filter['PRODUCTS']);
399 }
400
401 if
402 (
403 !empty($filter['REPORT_INTERVAL_from'])
404 && !empty($filter['REPORT_INTERVAL_to'])
405 )
406 {
407 $formattedFilter['REPORT_INTERVAL'] = [
408 'FROM' => $filter['REPORT_INTERVAL_from'],
409 'TO' => $filter['REPORT_INTERVAL_to'],
410 ];
411 }
412 return $formattedFilter;
413 }
414
415 private function getDefaultMeasure(): int
416 {
417 static $defaultMeasure = 0;
418
419 if (empty($defaultMeasure))
420 {
421 $fetchedMeasure = \CCatalogMeasure::getList([], ['=IS_DEFAULT' => 'Y'])->Fetch();
422 if ($fetchedMeasure)
423 {
424 $defaultMeasure = (int)$fetchedMeasure['ID'];
425 }
426 else
427 {
428 $defaultMeasure = 0;
429 }
430 }
431
432 return $defaultMeasure;
433 }
434
435 protected function prepareOverallTotals(array $storeTotals): array
436 {
437 $overallTotals = [];
438
439 foreach ($storeTotals as $storeTotalEntry)
440 {
441 foreach ($storeTotalEntry['TOTALS'] as $measureId => $total)
442 {
443 $startingQuantitySum = (float)$total['STARTING_QUANTITY'];
444 $amountSum = (float)$total['AMOUNT_SUM'];
445 $receivedQuantity = (float)$total['RECEIVED_QUANTITY'];
446 $quantityReservedSum = (float)$total['QUANTITY_RESERVED_SUM'];
447 $amountSoldSum = (float)$total['AMOUNT_SOLD'];
448
449 if (!isset($overallTotals[$measureId]))
450 {
451 $overallTotals[$measureId] = [
452 'STARTING_QUANTITY' => 0,
453 'RECEIVED_QUANTITY' => 0,
454 'AMOUNT_SUM' => 0,
455 'QUANTITY_RESERVED_SUM' => 0,
456 'AMOUNT_SOLD' => 0,
457 'QUANTITY' => 0,
458 ];
459 }
460 $overallTotals[$measureId]['STARTING_QUANTITY'] += $startingQuantitySum;
461 $overallTotals[$measureId]['RECEIVED_QUANTITY'] += $receivedQuantity;
462 $overallTotals[$measureId]['AMOUNT_SUM'] += $amountSum;
463 $overallTotals[$measureId]['QUANTITY_RESERVED_SUM'] += $quantityReservedSum;
464 $overallTotals[$measureId]['QUANTITY'] += $amountSum - $quantityReservedSum;
465 $overallTotals[$measureId]['AMOUNT_SOLD'] += $amountSoldSum;
466 }
467 }
468
469 return $overallTotals;
470 }
471
472 protected static function getAnalyticBoardByKey($key): ?AnalyticBoard
473 {
474 $boardProvider = new AnalyticBoardProvider();
475 $boardProvider->addFilter('boardKey', $key);
476
477 return $boardProvider->execute()->getFirstResult();
478 }
479
480 protected function getFilter(): Filter
481 {
482 static $filter;
483 if ($filter)
484 {
485 return $filter;
486 }
487
488 $boardKey = $this->getWidgetHandler()->getWidget()->getBoardId();
489 $board = self::getAnalyticBoardByKey($boardKey);
490 if ($board)
491 {
492 $filter = $board->getFilter();
493 }
494 else
495 {
496 $filter = new Filter($boardKey);
497 }
498
499 return $filter;
500 }
501
502 protected function getFilterParameters(): array
503 {
504 static $filterParameters = [];
505
506 $filter = $this->getFilter();
507 $filterId = $filter->getFilterParameters()['FILTER_ID'];
508
509 if (!$filterParameters[$filterId])
510 {
511 $options = new Options($filterId, $filter::getPresetsList());
512 $fieldList = $filter::getFieldsList();
513 $filterParameters[$filterId] = $options->getFilter($fieldList);
514 }
515
516 return $filterParameters[$filterId];
517 }
518
519 protected static function getNoAccessToStoresStub(): array
520 {
521 return [
522 'title' => Loc::getMessage('BASE_HANDLER_EMPTY_PERMITTED_STORES_LIST_STUB_TITLE'),
523 'description' => Loc::getMessage('BASE_HANDLER_EMPTY_PERMITTED_STORES_LIST_STUB_DESCRIPTION'),
524 ];
525 }
526
531 private static function getFilteredByRightsStoreList(?array $inputStoreList = null): ?array
532 {
533 $accessController = AccessController::getCurrent();
534
535 if (!$accessController->check(ActionDictionary::ACTION_STORE_VIEW))
536 {
537 return [];
538 }
539
540 if (!$accessController->checkCompleteRight(ActionDictionary::ACTION_STORE_VIEW))
541 {
542 $availableStores = $accessController->getPermissionValue(ActionDictionary::ACTION_STORE_VIEW) ?? [];
543
544 if (is_array($inputStoreList))
545 {
546 return array_values(array_intersect($availableStores, $inputStoreList));
547 }
548
549 return $availableStores;
550 }
551
552 return $inputStoreList;
553 }
554}
static formChartSliderUrl(string $componentName, array $filter)
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static getList(array $parameters=array())