Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
reportproductlist.php
1<?php
2
4
12use Bitrix\Main\Entity\Base;
13use Bitrix\Main\Entity\ReferenceField;
25
26abstract class ReportProductList extends ProductList
27{
28 protected int $storeId = 0;
29 protected string $navParamName = 'page';
30 protected array $catalogData = [];
31 protected array $defaultGridSort = ['PRODUCT_ID' => 'desc'];
32 protected string $reportFilterClass;
33 protected \Bitrix\Main\Grid\Options $gridOptions;
34
35 abstract protected function getGridId(): string;
36
37 abstract protected function getFilterId(): string;
38
39 abstract protected function prepareProductFilter(array $productIds): array;
40
41 abstract protected function getProductFilterDialogContext(): string;
42
43 abstract protected function getReceivedQuantityData(int $storeId, array $formattedFilter): array;
44
45 abstract protected function getOutgoingQuantityData(int $storeId, array $formattedFilter): array;
46
47 abstract protected function getAmountSoldData(int $storeId, array $formattedFilter): array;
48
49 abstract protected function getGridColumns(): array;
50
51 protected static function getEmptyStub(): string
52 {
53 return Loc::getMessage('CATALOG_REPORT_PRODUCT_LIST_NO_PRODUCTS');
54 }
55
56 public function onPrepareComponentParams($arParams)
57 {
58 $arParams['STORE_ID'] = (int)($arParams['STORE_ID'] ?? 0);
59
60 return parent::onPrepareComponentParams($arParams);
61 }
62
63 public function executeComponent()
64 {
65 if (!$this->checkModules())
66 {
67 $this->includeComponentTemplate();
68
69 return;
70 }
71
72 if (!$this->checkDocumentReadRights())
73 {
74 $this->arResult['ERROR_MESSAGES'][] = Loc::getMessage('CATALOG_REPORT_PRODUCT_LIST_NO_READ_RIGHTS_ERROR');
75
76 $this->includeComponentTemplate();
77
78 return;
79 }
80
81 $this->init();
82
83 $this->loadMeasures();
84 $this->arResult['GRID'] = $this->getGridData();
85 $this->arResult['STORE_TITLE'] = htmlspecialcharsbx($this->getStoreTitle());
86 if (empty($this->arResult['STORE_TITLE']))
87 {
88 $this->arResult['STORE_TITLE'] = Loc::getMessage('CATALOG_REPORT_PRODUCT_LIST_DEFAULT_STORE_NAME');
89 }
90
91 $filterOptions = [
92 'GRID_ID' => $this->getGridId(),
93 'FILTER_ID' => $this->getFilterId(),
94 'FILTER' => $this->getFilterFields(),
95 'FILTER_PRESETS' => [],
96 'ENABLE_LABEL' => true,
97 'THEME' => \Bitrix\Main\UI\Filter\Theme::LIGHT,
98 ];
99 $this->arResult['FILTER_OPTIONS'] = $filterOptions;
100
101 $this->includeComponentTemplate();
102 }
103
104 protected function checkModules(): bool
105 {
106 if (!Loader::includeModule('catalog'))
107 {
108 $this->arResult['ERROR_MESSAGES'][] = 'Module Catalog is not installed';
109
110 return false;
111 }
112
113 if (!Loader::includeModule('report'))
114 {
115 $this->arResult['ERROR_MESSAGES'][] = 'Module Report is not installed';
116
117 return false;
118 }
119
120 return true;
121 }
122
123 protected function getGridRows(): ?array
124 {
125 $productData = $this->getProductData();
126 if (!$productData)
127 {
128 return null;
129 }
130
131 $rows = [];
132
133 $this->catalogData = $this->loadCatalog(array_column($productData, 'PRODUCT_ID'));
134
135 $formattedFilter = $this->getFormattedFilter();
136 $receivedQuantityData = $this->getReceivedQuantityData($this->storeId, $formattedFilter);
137 $outgoingQuantityData = $this->getOutgoingQuantityData($this->storeId, $formattedFilter);
138 $amountSoldData = $this->getAmountSoldData($this->storeId, $formattedFilter);
139
140 $receivedQuantityAmountDifferenceData = [];
141 $outgoingQuantityAmountDifferenceData = [];
142 $amountSoldAmountDifferenceData = [];
143
144 if (!empty($formattedFilter['REPORT_INTERVAL']))
145 {
146 $differenceFilter = $formattedFilter;
147 $currentTime = new DateTime();
148 $filterTimeTo = new DateTime($differenceFilter['REPORT_INTERVAL']['TO']);
149 if ($currentTime > $filterTimeTo)
150 {
151 $differenceFilter['REPORT_INTERVAL']['FROM'] = $differenceFilter['REPORT_INTERVAL']['TO'];
152 $differenceFilter['REPORT_INTERVAL']['TO'] = (new DateTime())->toString();
153 $receivedQuantityAmountDifferenceData = $this->getReceivedQuantityData($this->storeId, $differenceFilter);
154 $outgoingQuantityAmountDifferenceData = $this->getOutgoingQuantityData($this->storeId, $differenceFilter);
155 $amountSoldAmountDifferenceData = $this->getAmountSoldData($this->storeId, $differenceFilter);
156 }
157 }
158
159 foreach ($productData as $key => $item)
160 {
161 $receivedQuantityAmountDifference = (float)($receivedQuantityAmountDifferenceData[$item['PRODUCT_ID']] ?? 0);
162 $outgoingQuantityAmountDifference = (float)($outgoingQuantityAmountDifferenceData[$item['PRODUCT_ID']] ?? 0);
163 $amountSoldAmountDifference = (float)($amountSoldAmountDifferenceData[$item['PRODUCT_ID']] ?? 0);
164 $item['AMOUNT'] =
165 $item['AMOUNT']
166 - $receivedQuantityAmountDifference
167 + $outgoingQuantityAmountDifference
168 + $amountSoldAmountDifference
169 ;
170
171 $receivedQuantity = (float)($receivedQuantityData[$item['PRODUCT_ID']] ?? 0);
172 $outgoingQuantity = (float)($outgoingQuantityData[$item['PRODUCT_ID']] ?? 0);
173 $amountSold = (float)($amountSoldData[$item['PRODUCT_ID']] ?? 0);
174 $item['STARTING_QUANTITY'] = (float)$item['AMOUNT'] - $receivedQuantity + $outgoingQuantity + $amountSold;
175 $item['RECEIVED_QUANTITY'] = (float)($receivedQuantityData[$item['PRODUCT_ID']] ?? 0);
176 $item['AMOUNT_SOLD'] = (float)($amountSoldData[$item['PRODUCT_ID']] ?? 0);
177 $item['QUANTITY'] = (float)$item['AMOUNT'] - (float)$item['QUANTITY_RESERVED'];
178 $rows[] = [
179 'id' => $item['ID'],
180 'data' => $item,
181 'columns' => $this->prepareItemColumn($item),
182 ];
183 }
184
185 return $rows;
186 }
187
188 protected function getGridData(): array
189 {
190 $navParams = $this->gridOptions->getNavParams();
191 $pageSize = (int)$navParams['nPageSize'];
192
193 $pageNavigation = new \Bitrix\Main\UI\PageNavigation($this->navParamName);
194 $pageNavigation->allowAllRecords(false)->setPageSize($pageSize)->initFromUri();
195
196 $totalCount = $this->getTotalCount();
197
198 $pageNavigation->setRecordCount($totalCount);
199 $gridRows = $this->getGridRows();
200 return [
201 'GRID_ID' => $this->getGridId(),
202 'COLUMNS' => $this->getGridColumns(),
203 'ROWS' => $gridRows,
204 'STUB' => $totalCount <= 0 ? ['title' => static::getEmptyStub()] : null,
205
206 'NAV_PARAM_NAME' => $this->navParamName,
207 'CURRENT_PAGE' => $pageNavigation->getCurrentPage(),
208 'NAV_OBJECT' => $pageNavigation,
209 'TOTAL_ROWS_COUNT' => $totalCount,
210 'AJAX_MODE' => 'Y',
211 'ALLOW_ROWS_SORT' => false,
212 'AJAX_OPTION_JUMP' => 'N',
213 'AJAX_OPTION_STYLE' => 'N',
214 'AJAX_OPTION_HISTORY' => 'N',
215 'AJAX_ID' => \CAjax::GetComponentID('bitrix:main.ui.grid', '', ''),
216 'SHOW_PAGINATION' => $totalCount > 0,
217 'SHOW_NAVIGATION_PANEL' => true,
218 'SHOW_PAGESIZE' => true,
219
220 'PAGE_SIZES' => [
221 ['NAME' => '10', 'VALUE' => '10'],
222 ['NAME' => '20', 'VALUE' => '20'],
223 ['NAME' => '50', 'VALUE' => '50'],
224 ['NAME' => '100', 'VALUE' => '100'],
225 ['NAME' => '200', 'VALUE' => '200'],
226 ['NAME' => '500', 'VALUE' => '500'],
227 ],
228
229 'SHOW_ROW_CHECKBOXES' => false,
230 'SHOW_CHECK_ALL_CHECKBOXES' => false,
231 'SHOW_ACTION_PANEL' => false,
232 'SHOW_GRID_SETTINGS_MENU' => false,
233 'SHOW_SELECTED_COUNTER' => false,
234 'HANDLE_RESPONSE_ERRORS' => true,
235 'ALLOW_STICKED_COLUMNS' => true,
236 ];
237 }
238
239 protected function getProductData(): array
240 {
241 $navParams = $this->gridOptions->getNavParams();
242 $pageSize = (int)$navParams['nPageSize'];
243 $gridSort = $this->gridOptions->GetSorting(['sort' => $this->defaultGridSort]);
244
245 $pageNavigation = new \Bitrix\Main\UI\PageNavigation($this->navParamName);
246 $pageNavigation->allowAllRecords(false)->setPageSize($pageSize)->initFromUri();
247
248 $this->arResult['GRID']['ROWS'] = [];
249
250 $offset = $pageNavigation->getOffset();
251 $order = $gridSort['sort'];
252 $limit = $pageNavigation->getLimit();
253
254 $query = $this->buildDataQuery($order, $limit, $offset);
255
256 return $query->exec()->fetchAll();
257 }
258
270 protected function buildDataQuery($order = null, $limit = null, $offset = null): Query
271 {
273
274 $filter = $this->getListFilter();
275 $baseStoreFilterValues = $filter['=STORE_ID'];
276 unset($filter['=STORE_ID']);
277 $reportInterval = $filter['REPORT_INTERVAL'] ?? [];
278 unset($filter['REPORT_INTERVAL']);
279
280 $storeDocsFilter = ['=DOCUMENT.STATUS' => 'Y'];
281 $shipmentsFilter = ['=ORDER_DELIVERY.DEDUCTED' => 'Y'];
282
283 if (!empty($reportInterval))
284 {
285 $storeDocsFilter += [
286 '<=DOCUMENT.DATE_STATUS' => new DateTime($reportInterval['TO']),
287 ];
288 $shipmentsFilter += [
289 '<=ORDER_DELIVERY.DATE_DEDUCTED' => new DateTime($reportInterval['TO']),
290 ];
291 }
292
293 if (!$this->isAllStoresGrid())
294 {
295 $storeDocsFilter[] = [
296 'LOGIC' => 'OR',
297 '=DOCS_ELEMENT.STORE_FROM' => $storeId,
298 '=DOCS_ELEMENT.STORE_TO' => $storeId,
299 ];
300
301 $shipmentsFilter['=STORE_BARCODE.STORE_ID'] = $storeId;
302 $filter[] = ['=STORE_ID' => $storeId];
303 }
304 elseif (!empty($baseStoreFilterValues))
305 {
306 $storeDocsFilter[] = $baseStoreFilterValues;
307 $shipmentsFilter['=STORE_BARCODE.STORE_ID'] = $baseStoreFilterValues;
308 $filter[] = ['=STORE_ID' => $baseStoreFilterValues];
309 }
310
311 $filter[] = [
312 'LOGIC' => 'OR',
313 $storeDocsFilter,
314 $shipmentsFilter
315 ];
316
317 $storeQuery = StoreProductTable::query();
318 $storeQuery->setSelect(['ID' ,'PRODUCT_ID', 'AMOUNT', 'QUANTITY_RESERVED', 'MEASURE_ID' => 'PRODUCT.MEASURE']);
319 $storeQuery->registerRuntimeField(
320 new Reference(
321 'DOCS_ELEMENT',
322 StoreDocumentElementTable::class,
323 Join::on('this.PRODUCT_ID', 'ref.ELEMENT_ID')
324 )
325 );
326 $storeQuery->registerRuntimeField(
327 new Reference(
328 'DOCUMENT',
329 StoreDocumentTable::class,
330 Join::on('this.DOCS_ELEMENT.DOC_ID', 'ref.ID')
331 )
332 );
333 $storeQuery->registerRuntimeField(
334 new Reference(
335 'BASKET',
336 BasketTable::class,
337 Join::on('this.PRODUCT_ID', 'ref.PRODUCT_ID')
338 )
339 );
340 $storeQuery->registerRuntimeField(
341 new Reference(
342 'SHIPMENT_ITEM',
343 ShipmentItemTable::class,
344 Join::on('this.BASKET.ID', 'ref.BASKET_ID')
345 )
346 );
347 $storeQuery->registerRuntimeField(
348 new Reference(
349 'STORE_BARCODE',
350 ShipmentItemStoreTable::class,
351 Join::on('this.SHIPMENT_ITEM.ID', 'ref.ORDER_DELIVERY_BASKET_ID')
352 )
353 );
354 $storeQuery->registerRuntimeField(
355 new Reference(
356 'ORDER_DELIVERY',
357 ShipmentTable::class,
358 Join::on('this.SHIPMENT_ITEM.ORDER_DELIVERY_ID', 'ref.ID')
359 )
360 );
361
362 $storeQuery->setFilter($filter);
363 $storeQuery->setDistinct();
364
365 if (!$this->isAllStoresGrid())
366 {
367 if (isset($order))
368 {
369 $storeQuery->setOrder($order);
370 }
371 if (isset($limit))
372 {
373 $storeQuery->setLimit($limit);
374 }
375 if (isset($offset))
376 {
377 $storeQuery->setOffset($offset);
378 }
379
380 $storeQuery->countTotal(true);
381
382 return $storeQuery;
383 }
384
385 $allStoreQuery = ProductTable::query();
386 $allStoreQuery->registerRuntimeField('',
387 new ReferenceField(
388 'SUBQUERY',
389 Base::getInstanceByQuery($storeQuery),
390 ['this.ID' => 'ref.PRODUCT_ID'],
391 ['join_type' => 'INNER']
392 )
393 );
394
395 $allStoreQuery->registerRuntimeField(
396 new \Bitrix\Main\Entity\ExpressionField(
397 'AMOUNT',
398 'SUM(%s)',
399 'SUBQUERY.AMOUNT'
400 )
401 );
402
403 $allStoreQuery->registerRuntimeField(
404 new \Bitrix\Main\Entity\ExpressionField(
405 'QUANTITY_RESERVED',
406 'SUM(%s)',
407 'SUBQUERY.QUANTITY_RESERVED'
408 )
409 );
410
411 $allStoreQuery->setSelect([
412 'ID',
413 'PRODUCT_ID' => 'ID',
414 'AMOUNT',
415 'QUANTITY_RESERVED',
416 'MEASURE_ID' => 'MEASURE',
417 ]);
418
419 if (isset($order))
420 {
421 $allStoreQuery->setOrder($order);
422 }
423
424 if (isset($limit))
425 {
426 $allStoreQuery->setLimit($limit);
427 }
428
429 if (isset($offset))
430 {
431 $allStoreQuery->setOffset($offset);
432 }
433
434 $allStoreQuery->countTotal(true);
435
436 return $allStoreQuery;
437 }
438
439 protected function getFormattedFilter(): array
440 {
441 $result = [];
442
443 $incomingFilter = $this->arParams['INCOMING_FILTER'] ?? [];
444
445 if (!empty($incomingFilter))
446 {
447 if (!empty($incomingFilter['PRODUCTS']))
448 {
449 $result['PRODUCTS'] = $this->prepareProductFilter($incomingFilter['PRODUCTS']);
450 }
451
452 if
453 (
454 !empty($incomingFilter['REPORT_INTERVAL_from'])
455 && !empty($incomingFilter['REPORT_INTERVAL_to'])
456 )
457 {
458 $result['REPORT_INTERVAL'] = [
459 'FROM' => $incomingFilter['REPORT_INTERVAL_from'],
460 'TO' => $incomingFilter['REPORT_INTERVAL_to'],
461 ];
462 }
463
464 if (!empty($incomingFilter['STORES']) && $this->isAllStoresGrid())
465 {
466 $result['STORE_ID'] = $incomingFilter['STORES'];
467 }
468 }
469 else
470 {
471 $getListFilter = $this->getListFilter();
472 if (!empty($getListFilter['=PRODUCT_ID']))
473 {
474 $result['PRODUCTS'] = $getListFilter['=PRODUCT_ID'];
475 }
476
477 $userFilter = $this->getUserFilter();
478 if
479 (
480 !empty($userFilter['>=REPORT_INTERVAL'])
481 && !empty($userFilter['<=REPORT_INTERVAL'])
482 )
483 {
484 $result['REPORT_INTERVAL'] = [
485 'FROM' => $userFilter['>=REPORT_INTERVAL'],
486 'TO' => $userFilter['<=REPORT_INTERVAL'],
487 ];
488 }
489 }
490
491 return $result;
492 }
493
494 protected function prepareItemColumn(array $item): array
495 {
496 $column = $item;
497
498 $column['PRODUCT_ID'] = $this->getProductView($column);
499
500 foreach (['STARTING_QUANTITY', 'RECEIVED_QUANTITY', 'AMOUNT', 'QUANTITY_RESERVED', 'QUANTITY', 'AMOUNT_SOLD'] as $totalField)
501 {
502 $column[$totalField] = $this->formatNumberWithMeasure($column[$totalField], (int)$column['MEASURE_ID']);
503 }
504
505 unset($column['MEASURE_ID']);
506
507 $column['QUANTITY_RESERVED'] = $this->getReservedDealListLink((int)$item['PRODUCT_ID'], $column['QUANTITY_RESERVED']);
508
509 return $column;
510 }
511
512 protected function getReservedDealListLink(int $productId, string $quantityReservedView): string
513 {
514 return
515 '<a
516 class="main-grid-cell-content-store-amount-reserved-quantity"
517 onclick="BX.SidePanel.Instance.open(\'' . $this->getReservedDealsSliderLink($productId) . '\')"
518 >' . $quantityReservedView . '</a>'
519 ;
520 }
521
522 protected function getReservedDealsSliderLink(int $productId): string
523 {
524 $sliderUrl = \CComponentEngine::makeComponentPath('bitrix:catalog.productcard.reserved.deal.list');
525 $sliderUrl = getLocalPath('components'.$sliderUrl.'/slider.php');
526 $sliderUrlEntity = new \Bitrix\Main\Web\Uri($sliderUrl);
527 $sliderUrlEntity->addParams([
528 'storeId' => $this->storeId,
529 'productId' => $productId,
530 ]);
531
532 return $sliderUrlEntity->getUri();
533 }
534
535 protected function formatNumberWithMeasure($number, int $measureId)
536 {
537 if (!$measureId)
538 {
539 $measureId = $this->getDefaultMeasure()['ID'];
540 }
541 return Loc::getMessage(
542 'CATALOG_REPORT_PRODUCT_LIST_MEASURE_TEMPLATE',
543 [
544 '#NUMBER#' => $number,
545 '#MEASURE_SYMBOL#' => $this->getMeasureSymbol($measureId),
546 ]
547 );
548 }
549
550 protected function getMeasureSymbol(int $measureId): string
551 {
552 return htmlspecialcharsbx($this->measures[$measureId]['SYMBOL']);
553 }
554
555 protected function getProductView(array $column): string
556 {
557 global $APPLICATION;
558
559 $product = $this->catalogData[(int)$column['PRODUCT_ID']];
560
561 ob_start();
562 $APPLICATION->IncludeComponent(
563 'bitrix:catalog.grid.product.field',
564 '',
565 [
566 'BUILDER_CONTEXT' => $this->arParams['BUILDER_CONTEXT'],
567 'GRID_ID' => $this->getGridId(),
568 'ROW_ID' => $column['ID'],
569 'GUID' => 'catalog_document_grid_' . $column['ID'],
570 'PRODUCT_FIELDS' => [
571 'ID' => $product['FIELDS']['PRODUCT_ID'],
572 'NAME' => $product['FIELDS']['NAME'],
573 'IBLOCK_ID' => $product['FIELDS']['IBLOCK_ID'],
574 'SKU_IBLOCK_ID' => $product['FIELDS']['OFFERS_IBLOCK_ID'],
575 'SKU_ID' => $product['FIELDS']['OFFER_ID'],
576 'BASE_PRICE_ID' => $product['FIELDS']['BASE_PRICE_ID'],
577 ],
578 'SKU_TREE' => $product['FIELDS']['SKU_TREE'],
579 'MODE' => 'view',
580 'VIEW_FORMAT' => 'short',
581 'ENABLE_SEARCH' => false,
582 'ENABLE_IMAGE_CHANGE_SAVING' => false,
583 'ENABLE_IMAGE_INPUT' => false,
584 'ENABLE_INPUT_DETAIL_LINK' => true,
585 'ENABLE_EMPTY_PRODUCT_ERROR' => false,
586 'ENABLE_SKU_SELECTION' => false,
587 'HIDE_UNSELECTED_ITEMS' => true,
588 'IS_NEW' => false,
589 ]
590 );
591
592 return ob_get_clean();
593 }
594
595 protected function init(): void
596 {
597 $this->storeId = $this->arParams['STORE_ID'];
598 $this->gridOptions = new \Bitrix\Main\Grid\Options($this->getGridId());
599
600 if ($this->arParams['OPENED_FROM_REPORT'])
601 {
602 $this->getFilterOptions()->reset();
603 }
604
605 if (isset($this->arParams['INCOMING_FILTER']) && is_array($this->arParams['INCOMING_FILTER']))
606 {
607 $this->initFilterFromIncomingData($this->arParams['INCOMING_FILTER']);
608 }
609 }
610
611 protected function isAllStoresGrid(): bool
612 {
613 return $this->storeId <= 0;
614 }
615
616 protected function prepareFilterIncomingData(array $incomingFilter): array
617 {
618 $filterFields = [];
619 if (isset($incomingFilter['PRODUCTS'], $incomingFilter['PRODUCTS_label']))
620 {
621 $filterFields['PRODUCTS'] = $incomingFilter['PRODUCTS'];
622 $filterFields['PRODUCTS_label'] = $incomingFilter['PRODUCTS_label'];
623 }
624
625 return $filterFields;
626 }
627
628 protected function initFilterFromIncomingData(array $incomingFilter): void
629 {
630 $filterFields = $this->prepareFilterIncomingData($incomingFilter);
631
632 if (count($filterFields) > 0)
633 {
634 $this->setFilterFields($filterFields);
635 }
636 }
637
638 protected function setFilterFields(array $filterFields): void
639 {
640 $filterOptions = $this->getFilterOptions();
641 $currentFilterSettings = $filterOptions->getFilterSettings('tmp_filter');
642 $currentFilterSettings['fields'] = $filterFields;
643 $filterOptions->setFilterSettings(
644 \Bitrix\Main\UI\Filter\Options::TMP_FILTER,
645 $currentFilterSettings,
646 true,
647 false
648 );
649 $filterOptions->save();
650 }
651
652 protected function checkDocumentReadRights(): bool
653 {
654 if (
655 !AccessController::getCurrent()->check(ActionDictionary::ACTION_CATALOG_READ)
656 || !AccessController::getCurrent()->check(ActionDictionary::ACTION_INVENTORY_MANAGEMENT_ACCESS)
657 )
658 {
659 return false;
660 }
661
662 return
663 $this->arParams['STORE_ID'] > 0
664 ? AccessController::getCurrent()->checkByValue(ActionDictionary::ACTION_STORE_VIEW, $this->arParams['STORE_ID'])
665 : AccessController::getCurrent()->check(ActionDictionary::ACTION_STORE_VIEW)
666 ;
667 }
668
669 protected function getTotalCount(): int
670 {
671 return $this->buildDataQuery()->exec()->getCount();
672 }
673
674 protected function getListFilter(): array
675 {
676 if (!$this->isAllStoresGrid())
677 {
678 $filter = [
679 '=STORE_ID' => $this->storeId,
680 ];
681 }
682 else
683 {
684 $filter =
685 AccessController::getCurrent()
686 ->getEntityFilter(
687 ActionDictionary::ACTION_STORE_VIEW,
688 StoreProductTable::class
689 )
690 ;
691
692 $incomingFilter = $this->arParams['INCOMING_FILTER'] ?? [];
693 if (isset($incomingFilter['STORES']))
694 {
695 $filter['=STORE_ID'] = $incomingFilter['STORES'];
696 }
697 }
698
699 $searchString = trim($this->getFilterOptions()->getSearchString());
700 if ($searchString)
701 {
702 $filter['%PRODUCT.IBLOCK_ELEMENT.SEARCHABLE_CONTENT'] = mb_strtoupper($searchString);
703 }
704
705 $userFilter = $this->getUserFilter();
706 if (!empty($userFilter['PRODUCTS']))
707 {
708 $filter['=PRODUCT_ID'] = $this->prepareProductFilter($userFilter['PRODUCTS']);
709 }
710
711 if
712 (
713 !empty($userFilter['>=REPORT_INTERVAL'])
714 && !empty($userFilter['<=REPORT_INTERVAL'])
715 )
716 {
717 $filter['REPORT_INTERVAL'] = [
718 'FROM' => $userFilter['>=REPORT_INTERVAL'],
719 'TO' => $userFilter['<=REPORT_INTERVAL'],
720 ];
721 }
722
723 return $filter;
724 }
725
726 protected function getStoreTitle(): string
727 {
728 $storeData = \Bitrix\Catalog\StoreTable::getList([
729 'select' => ['TITLE'],
730 'filter' => ['=ID' => $this->storeId],
731 'limit' => 1,
732 ])->fetch();
733
734 return $storeData['TITLE'] ?? '';
735 }
736
737 protected function getFilterFields(): array
738 {
739 $entities = [];
740
741 if (Loader::includeModule('crm'))
742 {
743 $entities[] = [
744 'id' => 'product_variation',
745 'options' => [
746 'iblockId' => \Bitrix\Crm\Product\Catalog::getDefaultId(),
747 'basePriceId' => Catalog\GroupTable::getBasePriceTypeId(),
748 'showPriceInCaption' => false,
749 ],
750 ];
751 }
752
753 return [
754 'PRODUCTS' => [
755 'id' => 'PRODUCTS',
756 'name' => Loc::getMessage('CATALOG_REPORT_PRODUCT_LIST_FILTER_PRODUCTS_TITLE'),
757 'type' => 'entity_selector',
758 'default' => true,
759 'partial' => true,
760 'params' => [
761 'multiple' => true,
762 'showDialogOnEmptyInput' => false,
763 'dropdownMode' => true,
764 'dialogOptions' => [
765 'hideOnSelect' => false,
766 'context' => $this->getProductFilterDialogContext(),
767 'entities' => $entities,
768 'recentTabOptions' => [
769 'stub' => true,
770 'stubOptions' => [
771 'title' => Loc::getMessage('CATALOG_REPORT_PRODUCT_LIST_PRODUCT_FILTER_STUB'),
772 ],
773 ],
774 'events' => [
775 'onBeforeSearch' => 'onBeforeDialogSearch',
776 ],
777 ],
778 ],
779 ]
780 ];
781 }
782
783 protected function getUserFilter(): array
784 {
785 $filterOptions = $this->getFilterOptions();
786 $filterFields = $this->getFilterFields();
787
788 return $filterOptions->getFilterLogic($filterFields);
789 }
790
791 protected function getFilterOptions(): \Bitrix\Main\UI\Filter\Options
792 {
793 static $filterOptions = null;
794 if (is_null($filterOptions))
795 {
796 $filterOptions = new \Bitrix\Main\UI\Filter\Options($this->getFilterId());
797 }
798
799 return $filterOptions;
800 }
801}
getAmountSoldData(int $storeId, array $formattedFilter)
getReceivedQuantityData(int $storeId, array $formattedFilter)
buildDataQuery($order=null, $limit=null, $offset=null)
getReservedDealListLink(int $productId, string $quantityReservedView)
getOutgoingQuantityData(int $storeId, array $formattedFilter)
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29