AnonSec Shell
Server IP : 85.193.89.191  /  Your IP : 18.216.90.222
Web Server : Apache
System : Linux 956367-cx40159.tmweb.ru 3.10.0-1160.105.1.el7.x86_64 #1 SMP Thu Dec 7 15:39:45 UTC 2023 x86_64
User : bitrix ( 600)
PHP Version : 8.1.27
Disable Function : NONE
MySQL : OFF  |  cURL : OFF  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /home/bitrix/www/bitrix/components/bitrix/catalog.store.document.list/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     

Current File : /home/bitrix/www/bitrix/components/bitrix/catalog.store.document.list/class.php
<?php

use Bitrix\Catalog;
use Bitrix\Catalog\Access\AccessController;
use Bitrix\Catalog\Access\ActionDictionary;
use Bitrix\Catalog\Document\Type\StoreDocumentArrivalTable;
use Bitrix\Catalog\Document\Type\StoreDocumentDeductTable;
use Bitrix\Catalog\Document\Type\StoreDocumentMovingTable;
use Bitrix\Catalog\Document\Type\StoreDocumentStoreAdjustmentTable;
use Bitrix\Catalog\Config\Feature;
use Bitrix\Catalog\StoreDocumentTable;
use Bitrix\Catalog\Url\InventoryManagementSourceBuilder;
use Bitrix\Main;
use Bitrix\Main\Context;
use Bitrix\Main\Engine\Contract\Controllerable;
use Bitrix\Main\Entity\ReferenceField;
use Bitrix\Main\Loader;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Type\DateTime;
use Bitrix\Main\Web\Json;
use Bitrix\Main\Web\Uri;
use Bitrix\UI\Buttons\CreateButton;
use Bitrix\UI\Buttons\LockedButton;
use Bitrix\Catalog\v2\Contractor\Provider\Manager;
use Bitrix\Catalog\ContractorTable;
use Bitrix\Catalog\Filter\Factory\DocumentFilterFactory;
use Bitrix\Catalog\StoreTable;
use Bitrix\Main\Filter\Settings;
use Bitrix\UI\Buttons\SettingsButton;
use Bitrix\UI\Toolbar\Facade\Toolbar;

if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
{
	die();
}

Loader::includeModule('catalog');
Loader::includeModule('currency');

class CatalogStoreDocumentListComponent extends CBitrixComponent implements Controllerable
{
	private const GRID_ID = 'catalog_store_documents';
	private const FILTER_ID = 'catalog_store_documents_filter';

	public const ARRIVAL_MODE = 'receipt_adjustment';
	public const MOVING_MODE = 'moving';
	public const DEDUCT_MODE = 'deduct';
	/**
	 * @deprecated not used
	 */
	public const OTHER_MODE = 'other';

	private $defaultGridSort = [
		'DATE_MODIFY' => 'desc',
	];
	private $navParamName = 'page';

	/** @var \Bitrix\Catalog\Filter\DataProvider\DocumentDataProvider $itemProvider */
	private $itemProvider;
	/** @var \Bitrix\Catalog\Filter\DocumentFilter $filter */
	private $filter;
	/** @var array $contractors */
	private $contractors;
	/** @var array $stores */
	private $stores;
	/** @var string $mode */
	private $mode;
	/** @var array $documentStores */
	private $documentStores;

	/** @var AccessController */
	private $accessController;

	private array $fieldWhitelist = [];

	public function __construct($component = null)
	{
		parent::__construct($component);

		$this->accessController = AccessController::getCurrent();
	}

	public function onPrepareComponentParams($arParams)
	{
		if (!isset($arParams['PATH_TO']))
		{
			$arParams['PATH_TO'] = [];
		}
		return parent::onPrepareComponentParams($arParams);
	}

	public function executeComponent()
	{
		$crmIncluded = Loader::includeModule('crm');
		if ($crmIncluded)
		{
			CCrmInvoice::installExternalEntities();
		}

		$this->init();

		$this->checkIfInventoryManagementIsDisabled();

		if (!$this->checkDocumentReadRights())
		{
			if ($crmIncluded)
			{
				$this->arResult['ERROR_MESSAGES'][] = [
					'TITLE' => Loc::getMessage(
						'DOCUMENT_LIST_ERR_ACCESS_DENIED',
						['#DOCUMENT_TYPE_NAME#' => $this->getModeName()]
					),
					'HELPER_CODE' => 15955386,
					'LESSON_ID' => 25010,
					'COURSE_ID' => 48,
				];
			}
			else
			{
				$this->arResult['ERROR_MESSAGES'][] = Loc::getMessage('DOCUMENT_LIST_NO_VIEW_RIGHTS_ERROR');
			}
			$this->includeComponentTemplate();

			return;
		}
		$this->arResult['GRID'] = $this->prepareGrid();
		$this->arResult['FILTER_ID'] = $this->getFilterId();
		$this->prepareToolbar();
		$this->arResult['IS_SHOW_GUIDE'] = $this->isShowGuide();
		$this->arResult['IS_SHOW_PRODUCT_BATCH_METHOD_POPUP'] = $this->isShowProductBatchMethodPopup();
		$this->arResult['IS_SHOW_PROFIT_REPORT_TOUR'] = $this->isShowProfitReportTour();

		$this->arResult['PATH_TO'] = $this->arParams['PATH_TO'];

		$this->arResult['INVENTORY_MANAGEMENT_SOURCE'] =
			InventoryManagementSourceBuilder::getInstance()->getInventoryManagementSource()
		;

		$this->initInventoryManagementSlider();

		$this->includeComponentTemplate();
	}

	private function checkIfInventoryManagementIsDisabled(): void
	{
		$this->arResult['IS_INVENTORY_MANAGEMENT_DISABLED'] = !Feature::isInventoryManagementEnabled();
		if ($this->arResult['IS_INVENTORY_MANAGEMENT_DISABLED'])
		{
			$this->arResult['INVENTORY_MANAGEMENT_FEATURE_SLIDER_CODE'] = Feature::getInventoryManagementHelpLink()['FEATURE_CODE'] ?? null;
		}
		else
		{
			$this->arResult['INVENTORY_MANAGEMENT_FEATURE_SLIDER_CODE'] = null;
		}
	}

	/**
	 * Localized mode name.
	 *
	 * @return string
	 */
	private function getModeName(): string
	{
		if ($this->mode === self::ARRIVAL_MODE)
		{
			$type = StoreDocumentTable::TYPE_ARRIVAL;
		}
		elseif ($this->mode === self::MOVING_MODE)
		{
			$type = StoreDocumentTable::TYPE_MOVING;
		}
		elseif ($this->mode === self::DEDUCT_MODE)
		{
			$type = StoreDocumentTable::TYPE_DEDUCT;
		}
		else
		{
			return '';
		}

		return (string)Loc::getMessage('DOCUMENT_LIST_DOC_TYPE_' . $type);
	}

	private function checkDocumentAccessRights(string $action): bool
	{
		if (
			!$this->accessController->check(ActionDictionary::ACTION_CATALOG_READ)
			|| !$this->accessController->check(ActionDictionary::ACTION_INVENTORY_MANAGEMENT_ACCESS)
		)
		{
			return false;
		}

		switch ($this->mode)
		{
			case self::ARRIVAL_MODE:
				return
					$this->accessController->checkByValue($action, StoreDocumentTable::TYPE_ARRIVAL)
					|| $this->accessController->checkByValue($action, StoreDocumentTable::TYPE_STORE_ADJUSTMENT)
					;

			case self::MOVING_MODE:
				return $this->accessController->checkByValue(
					$action,
					StoreDocumentTable::TYPE_MOVING
				);

			case self::DEDUCT_MODE:
				return $this->accessController->checkByValue(
					$action,
					StoreDocumentTable::TYPE_DEDUCT
				);

			case self::OTHER_MODE:
				return
					$this->accessController->checkByValue($action, StoreDocumentTable::TYPE_RETURN)
					|| $this->accessController->checkByValue($action, StoreDocumentTable::TYPE_UNDO_RESERVE)
					;
		}

		return false;
	}

	private function checkDocumentReadRights(): bool
	{
		return $this->checkDocumentAccessRights(ActionDictionary::ACTION_STORE_DOCUMENT_VIEW);
	}

	private function checkDocumentModifyRights(): bool
	{
		return $this->checkDocumentAccessRights(ActionDictionary::ACTION_STORE_DOCUMENT_MODIFY);
	}

	private function checkDocumentDeleteRights(): bool
	{
		return $this->checkDocumentAccessRights(ActionDictionary::ACTION_STORE_DOCUMENT_DELETE);
	}

	private function checkDocumentConductRights(): bool
	{
		return $this->checkDocumentAccessRights(ActionDictionary::ACTION_STORE_DOCUMENT_CONDUCT);
	}

	private function checkDocumentCancelRights(): bool
	{
		return $this->checkDocumentAccessRights(ActionDictionary::ACTION_STORE_DOCUMENT_CANCEL);
	}

	public function configureActions()
	{
	}

	private function getFilterId(): string
	{
		return self::FILTER_ID . '_' . $this->mode;
	}

	private function getGridId(): string
	{
		return self::GRID_ID . '_' . $this->mode;
	}

	private function init()
	{
		$this->initMode();

		$settings = new Settings([
			'ID' => $this->getFilterId(),
		]);

		$ufProviderSettings = [];
		$defaultSettingsParams = ['ID' => 0];
		switch ($this->mode)
		{
			case self::ARRIVAL_MODE:
				$ufProviderSettings[] = new Catalog\Filter\DataProvider\EntitySettings\ArrivalDocumentSettings($defaultSettingsParams);
				$ufProviderSettings[] = new Catalog\Filter\DataProvider\EntitySettings\StoreAdjustmentDocumentSettings($defaultSettingsParams);
				break;
			case self::MOVING_MODE:
				$ufProviderSettings[] = new Catalog\Filter\DataProvider\EntitySettings\MovingDocumentSettings($defaultSettingsParams);
				break;
			case self::DEDUCT_MODE:
				$ufProviderSettings[] = new Catalog\Filter\DataProvider\EntitySettings\DeductDocumentSettings($defaultSettingsParams);
				break;
		}

		$additionalProviders = [];
		foreach ($ufProviderSettings as $ufProviderSetting)
		{
			$additionalProviders[] = new Main\Filter\EntityUFDataProvider($ufProviderSetting);
		}

		$this->filter = (new DocumentFilterFactory)->createBySettings($this->mode, $settings, $additionalProviders);
		$this->itemProvider = $this->filter->getEntityDataProvider();
	}

	private function initMode()
	{
		if ($this->arParams['MODE'] === self::ARRIVAL_MODE)
		{
			$this->mode = self::ARRIVAL_MODE;
		}
		elseif ($this->arParams['MODE'] === self::MOVING_MODE)
		{
			$this->mode = self::MOVING_MODE;
		}
		elseif ($this->arParams['MODE'] === self::DEDUCT_MODE)
		{
			$this->mode = self::DEDUCT_MODE;
		}
		elseif ($this->arParams['MODE'] === self::OTHER_MODE)
		{
			$this->mode = self::OTHER_MODE;
			// TODO: remove this hack after refactoring OTHER document section
			\Bitrix\Main\UI\Extension::load([
				'admin_interface',
				'sidepanel'
			]);
		}
		else
		{
			// todo: get first valid item from the menu?
			$this->mode = self::ARRIVAL_MODE;
		}

		$this->arResult['MODE'] = $this->mode;
	}

	private function getFieldWhitelist(): array
	{
		if (!empty($this->fieldWhitelist))
		{
			return $this->fieldWhitelist;
		}

		$commonWhitelistFields = ['STORES', 'PRODUCTS'];

		if ($this->mode === self::ARRIVAL_MODE)
		{
			$arrivalFields = StoreDocumentArrivalTable::getEntity()->getFields();
			foreach ($arrivalFields as $field)
			{
				$this->fieldWhitelist[] = $field->getName();
			}

			$adjsutmentFields = StoreDocumentStoreAdjustmentTable::getEntity()->getFields();
			foreach ($adjsutmentFields as $field)
			{
				$this->fieldWhitelist[] = $field->getName();
			}

			$this->fieldWhitelist = array_unique($this->fieldWhitelist);

			$this->fieldWhitelist = [
				...$this->fieldWhitelist,
				...$commonWhitelistFields,
				'CONTRACTOR_CRM_COMPANY_ID',
				'CONTRACTOR_CRM_CONTACT_ID',
			];

			return $this->fieldWhitelist;
		}

		$tableClass = StoreDocumentTable::class;
		switch ($this->mode)
		{
			case self::MOVING_MODE:
				$commonWhitelistFields[] = 'STORES_FROM';
				$commonWhitelistFields[] = 'STORES_TO';
				$tableClass = StoreDocumentMovingTable::class;
				break;
			case self::DEDUCT_MODE:
				$tableClass = StoreDocumentDeductTable::class;
				break;
		}

		$fields = $tableClass::getEntity()->getFields();
		foreach ($fields as $field)
		{
			$this->fieldWhitelist[] = $field->getName();
		}

		$this->fieldWhitelist = [
			...$this->fieldWhitelist,
			...$commonWhitelistFields,
		];

		return $this->fieldWhitelist;
	}

	private function checkFieldNameAgainstWhitelist(string $fieldName): bool
	{
		$whitelist = $this->getFieldWhitelist();
		$fieldName = trim($fieldName, '!=<>%*');
		return (in_array($fieldName, $whitelist, true) || mb_strpos($fieldName, '.') !== false);
	}

	private function prepareGrid(): array
	{
		$result = [];

		$gridId = $this->getGridId();
		$result['GRID_ID'] = $gridId;
		$gridColumns = $this->itemProvider->getGridColumns();

		$gridOptions = new Bitrix\Main\Grid\Options($gridId);
		$navParams = $gridOptions->getNavParams();
		$pageSize = (int)$navParams['nPageSize'];
		$gridSort = $gridOptions->GetSorting(['sort' => $this->defaultGridSort]);

		$sortField = key($gridSort['sort']);
		foreach ($gridColumns as $key => $column)
		{
			if ($column['sort'] === $sortField)
			{
				$gridColumns[$key]['color'] = Bitrix\Main\Grid\Column\Color::BLUE;
				break;
			}
		}
		switch ($sortField)
		{
			case 'STATUS':
				$direction = $gridSort['sort'][$sortField];
				$gridSort['sort'] = [
					'STATUS' => $direction,
					'WAS_CANCELLED' => $direction,
					'ID' => 'DESC',
				];
				break;
			case 'ID':
				break;
			default:
				$gridSort['sort']['ID'] = 'DESC';
				break;
		}

		$result['COLUMNS'] = $gridColumns;

		$pageNavigation = new \Bitrix\Main\UI\PageNavigation($this->navParamName);
		$pageNavigation->allowAllRecords(false)->setPageSize($pageSize)->initFromUri();

		$this->arResult['GRID']['ROWS'] = [];
		$listFilter = $this->getListFilter();
		$filteredProducts = [];
		if (!empty($listFilter['PRODUCTS']))
		{
			$filteredProducts = $listFilter['PRODUCTS'];
			unset($listFilter['PRODUCTS']);
		}
		$filteredStores = [];
		if (!empty($listFilter['STORES']))
		{
			$filteredStores = $listFilter['STORES'];
			unset($listFilter['STORES']);
		}
		$filteredStoresFrom = [];
		if (!empty($listFilter['STORES_FROM']))
		{
			$filteredStoresFrom = $listFilter['STORES_FROM'];
			unset($listFilter['STORES_FROM']);
		}
		$filteredStoresTo = [];
		if (!empty($listFilter['STORES_TO']))
		{
			$filteredStoresTo = $listFilter['STORES_TO'];
			unset($listFilter['STORES_TO']);
		}
		$select = array_merge(['*'], $this->getUserSelectColumns($this->getUserReferenceColumns()));

		$tableClass = '';
		switch ($this->mode)
		{
			case self::MOVING_MODE:
				$tableClass = StoreDocumentMovingTable::class;
				break;
			case self::DEDUCT_MODE:
				$tableClass = StoreDocumentDeductTable::class;
				break;
			case self::ARRIVAL_MODE:
			case self::OTHER_MODE:
				$tableClass = StoreDocumentTable::class;
				break;
		}

		$query = $tableClass::query()
			->setFilter($listFilter)
		;

		if (!empty($filteredProducts))
		{
			$query->withProductList($filteredProducts);
		}
		if (!empty($filteredStores))
		{
			$query->withStoreList($filteredStores);
		}
		if (!empty($filteredStoresFrom))
		{
			$query->withStoreFromList($filteredStoresFrom);
		}
		if (!empty($filteredStoresTo))
		{
			$query->withStoreToList($filteredStoresTo);
		}

		foreach ($gridSort['sort'] as $fieldName => $sort)
		{
			if (!$this->checkFieldNameAgainstWhitelist($fieldName))
			{
				unset($gridSort['sort'][$fieldName]);
			}
		}

		$select = array_merge($select, ['UF_*']);
		$query
			->setSelect($select)
			->setOrder($gridSort['sort'])
			->setOffset($pageNavigation->getOffset())
			->setLimit($pageNavigation->getLimit())
		;

		if ($this->mode === self::ARRIVAL_MODE)
		{
			global $USER_FIELD_MANAGER;
			$arrivalUF = $USER_FIELD_MANAGER->GetUserFields(StoreDocumentArrivalTable::getUfId());
			$arrivalUF = array_column($arrivalUF, 'FIELD_NAME');
			if (!empty($arrivalUF))
			{
				$query->registerRuntimeField(
					new ReferenceField(
						'ARRIVAL',
						StoreDocumentArrivalTable::class,
						['=this.ID' => 'ref.ID'],
						['join_type' => 'inner']
					)
				);

				foreach ($arrivalUF as $fieldName)
				{
					$query->addSelect('ARRIVAL.' . $fieldName, $fieldName);
				}
			}

			$adjustmentsUF = $USER_FIELD_MANAGER->GetUserFields(StoreDocumentStoreAdjustmentTable::getUfId());
			$adjustmentsUF = array_column($adjustmentsUF, 'FIELD_NAME');
			if (!empty($adjustmentsUF))
			{
				$query->registerRuntimeField(
					new ReferenceField(
						'ADJUSTMENT',
						StoreDocumentStoreAdjustmentTable::class,
						['=this.ID' => 'ref.ID'],
						['join_type' => 'inner']
					)
				);

				foreach ($adjustmentsUF as $fieldName)
				{
					$query->addSelect('ADJUSTMENT.' . $fieldName, $fieldName);
				}
			}

			$query->whereIn('DOC_TYPE', [
				StoreDocumentArrivalTable::getType(), StoreDocumentStoreAdjustmentTable::getType()
			]);
		}

		$list = $query->fetchAll();
		$totalCount = $query->queryCountTotal();

		if ($totalCount > 0)
		{
			$this->loadDocumentStores(array_column($list, 'ID'));
			foreach($list as $item)
			{
				$result['ROWS'][] = [
					'id' => $item['ID'],
					'data' => $item,
					'columns' => $this->getItemColumn($item),
					'actions' => $this->getItemActions($item),
					'editable' => $this->accessController->checkByValue(ActionDictionary::ACTION_STORE_DOCUMENT_MODIFY, $item['DOC_TYPE'])
				];
			}
		}
		elseif ($this->mode !== self::OTHER_MODE)
		{
			$result['STUB'] = $this->getStub();
		}

		$pageNavigation->setRecordCount($totalCount);
		$result['NAV_PARAM_NAME'] = $this->navParamName;
		$result['CURRENT_PAGE'] = $pageNavigation->getCurrentPage();
		$result['NAV_OBJECT'] = $pageNavigation;
		$result['TOTAL_ROWS_COUNT'] = $totalCount;
		$result['AJAX_MODE'] = 'Y';
		$result['ALLOW_ROWS_SORT'] = false;
		$result['AJAX_OPTION_JUMP'] = "N";
		$result['AJAX_OPTION_STYLE'] = "N";
		$result['AJAX_OPTION_HISTORY'] = "N";
		$result['AJAX_ID'] = \CAjax::GetComponentID("bitrix:main.ui.grid", '', '');
		$result['SHOW_PAGINATION'] = $totalCount > 0;
		$result['SHOW_NAVIGATION_PANEL'] = true;
		$result['SHOW_PAGESIZE'] = true;
		$result['PAGE_SIZES'] = [['NAME' => 10, 'VALUE' => '10'], ['NAME' => 20, 'VALUE' => '20'], ['NAME' => 50, 'VALUE' => '50']];
		$result['SHOW_ROW_CHECKBOXES'] = true;
		$result['SHOW_CHECK_ALL_CHECKBOXES'] = true;
		$result['SHOW_ACTION_PANEL'] = true;

		$actionPanelItems = [];
		$snippet = new \Bitrix\Main\Grid\Panel\Snippet();
		if ($this->checkDocumentDeleteRights())
		{
			$removeButton = $snippet->getRemoveButton();
			$snippet->setButtonActions($removeButton, [
				[
					'ACTION' => \Bitrix\Main\Grid\Panel\Actions::CALLBACK,
					'CONFIRM' => true,
					'CONFIRM_APPLY_BUTTON' => Loc::getMessage('DOCUMENT_LIST_ACTION_DELETE_TEXT'),
					'DATA' => [
						[
							'JS' => 'BX.Catalog.DocumentGridManager.Instance.deleteSelectedDocuments()'
						],
					],
				]
			]);

			$actionPanelItems[] = $removeButton;
		}

		$dropdownActions = [];
		if ($this->checkDocumentConductRights())
		{
			$dropdownActions[] = [
				'NAME' => Loc::getMessage('DOCUMENT_LIST_CONDUCT_GROUP_ACTION'),
				'VALUE' => 'conduct',
			];
		}

		if ($this->checkDocumentCancelRights())
		{
			$dropdownActions[] = [
				'NAME' => Loc::getMessage('DOCUMENT_LIST_CANCEL_GROUP_ACTION'),
				'VALUE' => 'cancel',
			];
		}

		if ($dropdownActions)
		{
			array_unshift($dropdownActions, [
				'NAME' => Loc::getMessage('DOCUMENT_LIST_SELECT_GROUP_ACTION'),
				'VALUE' => 'none',
			]);

			$dropdownActionsButton = [
				'TYPE' => \Bitrix\Main\Grid\Panel\Types::DROPDOWN,
				'ID' => 'action_button_'. $this->getGridId(),
				'NAME' => 'action_button_'. $this->getGridId(),
				'ITEMS' => $dropdownActions,
			];

			$actionPanelItems[] = $dropdownActionsButton;

			$applyButton = $snippet->getApplyButton([
				'ONCHANGE' => [
					[
						'ACTION' => \Bitrix\Main\Grid\Panel\Actions::CALLBACK,
						'DATA' => [
							[
								'JS' => 'BX.Catalog.DocumentGridManager.Instance.processApplyButtonClick()',
							]
						]
					]
				]
			]);
			$actionPanelItems[] = $applyButton;
		}



		$result['ACTION_PANEL'] = [
			'GROUPS' => [
				[
					'ITEMS' => $actionPanelItems,
				],
			]
		];

		return $result;
	}

	private function getUserReferenceColumns(): array
	{
		return ['RESPONSIBLE', 'CREATED_BY_USER', 'MODIFIED_BY_USER', 'STATUS_BY_USER'];
	}

	private function getUserSelectColumns($userReferenceNames): array
	{
		$result = [];
		$fieldsToSelect = ['LOGIN', 'PERSONAL_PHOTO', 'NAME', 'SECOND_NAME', 'LAST_NAME'];

		foreach ($userReferenceNames as $userReferenceName)
		{
			foreach ($fieldsToSelect as $field)
			{
				$result[$userReferenceName . '_' . $field] = $userReferenceName . '.' . $field;
			}
		}

		return $result;
	}

	private function getItemActions($item): array
	{
		$labelText = $item['DOC_TYPE'] === StoreDocumentTable::TYPE_STORE_ADJUSTMENT
			? Loc::getMessage('DOCUMENT_LIST_DOC_TYPE_A')
			: Loc::getMessage('DOCUMENT_LIST_DOC_TYPE_' . $item['DOC_TYPE']);
		$urlToDocumentDetail = $this->getUrlToDocumentDetail($item['ID']);
		$sliderOptions = [
			'cacheable' => false,
		];
		if ($this->mode !== self::OTHER_MODE)
		{
			$sliderOptions['loader'] = 'crm-entity-details-loader';
			$sliderOptions['customLeftBoundary'] = 0;
			$sliderOptions['label'] = ['text' => $labelText];
		}
		$sliderOptions = \CUtil::PhpToJSObject($sliderOptions,false, false, true);
		$actions = [
			[
				'TITLE' => Loc::getMessage('DOCUMENT_LIST_ACTION_OPEN_TITLE'),
				'TEXT' => Loc::getMessage('DOCUMENT_LIST_ACTION_OPEN_TEXT'),
				'ONCLICK' => "BX.SidePanel.Instance.open('" . $urlToDocumentDetail . "', " . $sliderOptions . ")",
				'DEFAULT' => true,
			],
		];
		if ($item['STATUS'] === 'N')
		{
			if ($this->accessController->checkByValue(ActionDictionary::ACTION_STORE_DOCUMENT_CONDUCT, $item['DOC_TYPE']))
			{
				$actions[] = [
					'TITLE' => Loc::getMessage('DOCUMENT_LIST_ACTION_CONDUCT_TITLE'),
					'TEXT' => Loc::getMessage('DOCUMENT_LIST_ACTION_CONDUCT_TEXT'),
					'ONCLICK' => "BX.Catalog.DocumentGridManager.Instance.conductDocument(" . $item['ID'] . ", '" . $item['DOC_TYPE'] . "')",
				];
			}

			if ($this->accessController->checkByValue(ActionDictionary::ACTION_STORE_DOCUMENT_DELETE, $item['DOC_TYPE']))
			{
				$actions[] = [
					'TITLE' => Loc::getMessage('DOCUMENT_LIST_ACTION_DELETE_TITLE'),
					'TEXT' => Loc::getMessage('DOCUMENT_LIST_ACTION_DELETE_TEXT'),
					'ONCLICK' => "BX.Catalog.DocumentGridManager.Instance.deleteDocument(" . $item['ID'] . ")",
				];
			}
		}
		else
		{
			if ($this->accessController->checkByValue(ActionDictionary::ACTION_STORE_DOCUMENT_CANCEL, $item['DOC_TYPE']))
			{
				$actions[] = [
					'TITLE' => Loc::getMessage('DOCUMENT_LIST_ACTION_CANCEL_TITLE'),
					'TEXT' => Loc::getMessage('DOCUMENT_LIST_ACTION_CANCEL_TEXT'),
					'ONCLICK' => "BX.Catalog.DocumentGridManager.Instance.cancelDocument(" . $item['ID'] . ", '" . $item['DOC_TYPE'] . "')",
				];
			}
		}

		return $actions;
	}

	private function getStub()
	{
		if ($this->isUserFilterApplied() && $this->getTotalCountWithoutUserFilter() > 0)
		{
			return [
				'title' => Loc::getMessage('DOCUMENT_LIST_STUB_NO_DATA_TITLE'),
				'description' => Loc::getMessage('DOCUMENT_LIST_STUB_NO_DATA_DESCRIPTION'),
			];
		}

		switch ($this->mode)
		{
			case self::ARRIVAL_MODE:
				return '
				<div class="main-grid-empty-block-title">' . Loc::getMessage('DOCUMENT_LIST_STUB_TITLE_ARRIVAL_2') . '</div>
				<div class="main-grid-empty-block-description document-list-stub-description">' . Loc::getMessage('DOCUMENT_LIST_STUB_DESCRIPTION_ARRIVAL_2') . '</div>
				<div class="catalog-store-document-stub-transfer-content">
					<div class="catalog-store-document-stub-transfer-info">
						<div class="catalog-store-document-stub-transfer-info-text">
							' . Loc::getMessage('DOCUMENT_LIST_STUB_MIGRATION_TITLE') . '
						</div>
						' . $this->getStubLogoList() . '
					</div>
					<div class="catalog-store-document-stub-transfer-btn-block">
						<a href="#" onclick="openInventoryMarketplaceSlider()" class="ui-btn ui-btn-primary ui-btn-round">
							' . Loc::getMessage('DOCUMENT_LIST_STUB_MIGRATION_LINK') . '
						</a>
					</div>
				</div>
				';
			case self::MOVING_MODE:
				return '
					<div class="main-grid-empty-block-title">' . Loc::getMessage('DOCUMENT_LIST_STUB_TITLE_MOVING') . '</div>
					<div class="main-grid-empty-block-description document-list-stub-description">' . Loc::getMessage('DOCUMENT_LIST_STUB_DESCRIPTION_MOVING') . '</div>
					<a href="#" class="ui-link ui-link-dashed documents-grid-link" onclick="BX.Catalog.DocumentGridManager.Instance.openHowToControlGoodsMovement()">' . Loc::getMessage('DOCUMENT_LIST_STUB_LINK_CONTROL') . '</a>
				';
			case self::DEDUCT_MODE:
				return '
					<div class="main-grid-empty-block-title">' . Loc::getMessage('DOCUMENT_LIST_STUB_TITLE_DEDUCT') . '</div>
					<div class="main-grid-empty-block-description document-list-stub-description">' . Loc::getMessage('DOCUMENT_LIST_STUB_DESCRIPTION_DEDUCT') . '</div>
					<a href="#" class="ui-link ui-link-dashed documents-grid-link" onclick="BX.Catalog.DocumentGridManager.Instance.openHowToAccountForLosses()">' . Loc::getMessage('DOCUMENT_LIST_STUB_LINK_LOSSES') . '</a>
				';
			default:
				return [];
		}

	}

	private function getItemColumn($item)
	{
		$column = $item;

		$column['TITLE'] = $this->prepareTitleView($column);

		if ($column['DOC_NUMBER'])
		{
			$column['DOC_NUMBER'] = htmlspecialcharsbx($column['DOC_NUMBER']);
		}

		if ($column['DOC_TYPE'])
		{
			$columnDescription = [
				'text' => Loc::getMessage('DOCUMENT_LIST_DOC_TYPE_' . $column['DOC_TYPE']) ?: Loc::getMessage('DOCUMENT_LIST_DOC_TYPE_DEFAULT'),
				'color' => 'ui-label-light',
			];

			if ($this->mode === self::ARRIVAL_MODE)
			{
				$encodedFilter = Json::encode(
					[
						'DOC_TYPE' => [$column['DOC_TYPE']],
					],
					// JSON_FORCE_OBJECT flag has been added so that the output complies with the filter's API
					JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_FORCE_OBJECT
				);

				$columnDescription['events'] = [
					'click' => 'BX.delegate(function() {BX.Catalog.DocumentGridManager.Instance.applyFilter(' . $encodedFilter . ')})',
				];
			}

			$column['DOC_TYPE'] = [
				'DOC_TYPE_LABEL' => $columnDescription,
			];
		}

		if ($column['STATUS'])
		{
			if ($column['STATUS'] === 'N')
			{
				if ($column['WAS_CANCELLED'] === 'Y')
				{
					$labelColor = 'ui-label-lightorange';
					$labelText = Loc::getMessage('DOCUMENT_LIST_STATUS_CANCELLED');
					$filterLetter = 'C';
				}
				else
				{
					$labelColor = 'ui-label-light';
					$labelText = Loc::getMessage('DOCUMENT_LIST_STATUS_N');
					$filterLetter = 'N';
				}
			}
			else
			{
				$labelColor = 'ui-label-lightgreen';
				$labelText = Loc::getMessage('DOCUMENT_LIST_STATUS_Y');
				$filterLetter = 'Y';
			}

			$encodedFilter = Json::encode(
				[
					'STATUS' => [$filterLetter],
				],
				// JSON_FORCE_OBJECT flag has been added so that the output complies with the filter's API
				JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_FORCE_OBJECT
			);

			$labelColor .= ' label-uppercase';
			$column['STATUS'] = [
				'STATUS_LABEL' => [
					'text' => $labelText,
					'color' => $labelColor,
					'events' => [
						'click' => 'BX.delegate(function() {BX.Catalog.DocumentGridManager.Instance.applyFilter(' . $encodedFilter . ')})',
					],
				],
			];
		}

		$column['CONTRACTOR_ID'] = htmlspecialcharsbx($this->getContractorName($column));

		if (isset($column['TOTAL']))
		{
			$column['TOTAL'] = CCurrencyLang::CurrencyFormat($column['TOTAL'], $column['CURRENCY']);
		}
		else
		{
			$column['TOTAL'] = CCurrencyLang::CurrencyFormat(0, \Bitrix\Currency\CurrencyManager::getBaseCurrency());
		}

		if ($column['RESPONSIBLE_ID'])
		{
			$column['RESPONSIBLE_ID'] = $this->getUserDisplay($column, $column['RESPONSIBLE_ID'], 'RESPONSIBLE');
		}

		if ($column['CREATED_BY'])
		{
			$column['CREATED_BY'] = $this->getUserDisplay($column, $column['CREATED_BY'], 'CREATED_BY_USER');
		}

		if ($column['MODIFIED_BY'])
		{
			$column['MODIFIED_BY'] = $this->getUserDisplay($column, $column['MODIFIED_BY'], 'MODIFIED_BY_USER');
		}

		if ($column['STATUS_BY'])
		{
			$column['STATUS_BY'] = $this->getUserDisplay($column, $column['STATUS_BY'], 'STATUS_BY_USER');
		}

		if ($column['DATE_DOCUMENT'])
		{
			$column['DATE_DOCUMENT'] = (new \Bitrix\Main\Type\Date($column['DATE_DOCUMENT']))->toString();
		}

		$storesFrom = $this->documentStores[$column['ID']]['STORES_FROM'] ?? [];
		$storesTo = $this->documentStores[$column['ID']]['STORES_TO'] ?? [];
		$stores = array_unique(array_merge($storesFrom, $storesTo));
		if (!empty($stores))
		{
			if ($this->mode === self::MOVING_MODE)
			{
				$column = $this->addStoresToColumn($column, $storesFrom, 'STORES_FROM');
				$column = $this->addStoresToColumn($column, $storesTo, 'STORES_TO');
			}
			else
			{
				$column = $this->addStoresToColumn($column, $stores, 'STORES');
			}
		}

		return $column;
	}

	private function addStoresToColumn(array $column, array $stores, string $fieldName): array
	{
		$existingStores = $this->getStores();

		$resultColumn = $column;
		foreach ($stores as $store)
		{
			$existingStoreTitle = $existingStores[$store]['TITLE'] ?? '';

			$encodedFilter = Json::encode([
				$fieldName => [$store],
				$fieldName . '_label' => [$existingStoreTitle],
			]);
			$resultColumn[$fieldName][$fieldName . '_LABEL_' . $store] = [
				'text' => $existingStoreTitle ?: Loc::getMessage('DOCUMENT_LIST_EMPTY_STORE_TITLE'),
				'color' => 'ui-label-light',
				'events' => [
					'click' => 'BX.delegate(function() {BX.Catalog.DocumentGridManager.Instance.applyFilter(' . $encodedFilter . ')})',
				],
			];
		}

		return $resultColumn;
	}

	private function prepareTitleView($column): string
	{
		$urlToDocumentDetail = $this->getUrlToDocumentDetail($column['ID']);
		if ($column['TITLE'])
		{
			$result = '<a target="_top" href="' . $urlToDocumentDetail . '">' . htmlspecialcharsbx($column['TITLE']) . '</a>';
		}
		else
		{
			$result = '<a target="_top"  href="' . $urlToDocumentDetail . '">' . StoreDocumentTable::getTypeList(true)[$column['DOC_TYPE']] . '</a>';
		}

		$dateTimestamp = (new DateTime($column['DATE_CREATE']))->getTimestamp();
		$date = FormatDate(Context::getCurrent()->getCulture()->getLongDateFormat(), $dateTimestamp);
		$result .= '<div>' . Loc::getMessage('DOCUMENT_LIST_TITLE_DOCUMENT_DATE', ['#DATE#' => $date]) . '</div>';

		return $result;
	}

	private function getContractors(): array
	{
		if (!is_null($this->contractors))
		{
			return $this->contractors;
		}

		$this->contractors = [];

		$dbResult = ContractorTable::getList(['select' => ['ID', 'COMPANY', 'PERSON_NAME']]);
		while ($contractor = $dbResult->fetch())
		{
			$this->contractors[$contractor['ID']] = [
				'NAME' => $contractor['COMPANY'] ?: $contractor['PERSON_NAME'],
				'ID' => $contractor['ID'],
			];
		}

		return $this->contractors;
	}

	private function getStores(): array
	{
		if (!is_null($this->stores))
		{
			return $this->stores;
		}

		$this->stores = [];

		$dbResult = StoreTable::getList(['select' => ['ID', 'TITLE']]);
		while ($store = $dbResult->fetch())
		{
			$this->stores[$store['ID']] = [
				'TITLE' => $store['TITLE'],
				'ID' => $store['ID'],
			];
		}

		return $this->stores;
	}

	private function loadDocumentStores($documentIds): array
	{
		if (!is_null($this->documentStores))
		{
			return $this->documentStores;
		}

		$this->documentStores = [];

		$storesResult = \Bitrix\Catalog\StoreDocumentElementTable::getList([
			'select' => ['DOC_ID', 'STORE_FROM', 'STORE_TO'],
			'filter' => [
				'=DOC_ID' => $documentIds
			],
		]);
		while ($store = $storesResult->fetch())
		{
			$documentId = $store['DOC_ID'];
			if (!isset($this->documentStores[$documentId]))
			{
				$this->documentStores[$documentId] = [
					'STORES_FROM' => [],
					'STORES_TO' => [],
				];
			}

			if ($store['STORE_FROM'] && !in_array($store['STORE_FROM'], $this->documentStores[$documentId]['STORES_FROM'], true))
			{
				$this->documentStores[$documentId]['STORES_FROM'][] = $store['STORE_FROM'];
			}

			if ($store['STORE_TO'] && !in_array($store['STORE_TO'], $this->documentStores[$documentId]['STORES_TO'], true))
			{
				$this->documentStores[$documentId]['STORES_TO'][] = $store['STORE_TO'];
			}
		}

		return $this->documentStores;
	}

	private function getUserDisplay($column, $userId, $userReferenceName): string
	{
		$userEmptyAvatar = ' documents-grid-avatar-empty';
		$userAvatar = '';

		$userName = \CUser::FormatName(
			\CSite::GetNameFormat(false),
			[
				'LOGIN' => $column[$userReferenceName . '_LOGIN'],
				'NAME' => $column[$userReferenceName . '_NAME'],
				'LAST_NAME' => $column[$userReferenceName . '_LAST_NAME'],
				'SECOND_NAME' => $column[$userReferenceName . '_SECOND_NAME'],
			],
			true
		);

		$fileInfo = \CFile::ResizeImageGet(
			(int)$column[$userReferenceName . '_PERSONAL_PHOTO'],
			['width' => 60, 'height' => 60],
			BX_RESIZE_IMAGE_EXACT
		);
		if (is_array($fileInfo) && isset($fileInfo['src']))
		{
			$userEmptyAvatar = '';
			$photoUrl = $fileInfo['src'];
			$userAvatar = ' style="background-image: url(\'' . Uri::urnEncode($photoUrl) . '\')"';
		}

		$userNameElement = "<span class='documents-grid-avatar ui-icon ui-icon-common-user{$userEmptyAvatar}'><i{$userAvatar}></i></span>"
			."<span class='documents-grid-username-inner'>{$userName}</span>";

		return "<div class='documents-grid-username-wrapper'>"
			."<a class='documents-grid-username' href='/company/personal/user/{$userId}/'>{$userNameElement}</a>"
			."</div>";
	}

	private function getTotalCountWithoutUserFilter()
	{
		$filter = $this->getDocTypeModeFilter();

		$accessFilter = $this->getAccessFilter();
		if ($accessFilter)
		{
			$filter[] = $accessFilter;
		}

		return StoreDocumentTable::getCount($filter);
	}

	private function prepareToolbar()
	{
		$filterOptions = [
			'GRID_ID' => $this->getGridId(),
			'FILTER_ID' => $this->filter->getID(),
			'FILTER' => $this->filter->getFieldArrays(),
			'FILTER_PRESETS' => [],
			'ENABLE_LABEL' => true,
			'THEME' => Bitrix\Main\UI\Filter\Theme::LIGHT,
			'CONFIG' => [
				'AUTOFOCUS' => false,
			],
		];
		Toolbar::addFilter($filterOptions);

		$addDocumentButton = $this->getAddDocumentButton();
		if ($addDocumentButton)
		{
			Toolbar::addButton($addDocumentButton, \Bitrix\UI\Toolbar\ButtonLocation::AFTER_TITLE);
			$this->arResult['ADD_DOCUMENT_BTN_ID'] = $addDocumentButton->getUniqId();
		}

		$settingsButtonSettings = [
			'menu' => [
				'id' => 'docFieldsSettingsMenu',
				'items' => $this->getSettingsButtonMenuItems(),
			],
		];

		$menuButton = new SettingsButton($settingsButtonSettings);
		Toolbar::addButton($menuButton);
	}

	private function getAddDocumentButton(): ?\Bitrix\UI\Buttons\Button
	{
		if (!Feature::isInventoryManagementEnabled())
		{
			$btn = CreateButton::create([
				'text' => Loc::getMessage('DOCUMENT_LIST_ADD_DOCUMENT_BUTTON_2'),
				'color' => \Bitrix\UI\Buttons\Color::SUCCESS,
				'classList' => [
					'add-document-button',
					'ui-btn-icon-lock',
				],
			]);

			$inventoryManagementHelpLink = Feature::getInventoryManagementHelpLink();
			if (isset($inventoryManagementHelpLink['LINK']))
			{
				$btn->bindEvent('click', new \Bitrix\UI\Buttons\JsCode(
					"{$inventoryManagementHelpLink['LINK']}",
				));
			}
			return $btn;
		}

		if (!$this->checkDocumentModifyRights())
		{
			return LockedButton::create([
				'text' => Loc::getMessage('DOCUMENT_LIST_ADD_DOCUMENT_BUTTON_2'),
				'color' => \Bitrix\UI\Buttons\Color::SUCCESS,
				'hint' => Loc::getMessage('DOCUMENT_LIST_ADD_DOCUMENT_BUTTON_DISABLE_HINT'),
				'classList' => [
					'add-document-button',
					'add-document-button-disabled',
				],
			]);
		}

		$addDocumentButton = CreateButton::create([
			'text' => Loc::getMessage('DOCUMENT_LIST_ADD_DOCUMENT_BUTTON_2'),
			'color' => \Bitrix\UI\Buttons\Color::SUCCESS,
			'dataset' => [
				'toolbar-collapsed-icon' => \Bitrix\UI\Buttons\Icon::ADD,
			],
			'classList' => ['add-document-button'],
		]);

		if ($this->mode === self::OTHER_MODE)
		{
			$addDocumentButton->setMenu([
				'items' => [
					[
						'text' => StoreDocumentTable::getTypeList(true)[StoreDocumentTable::TYPE_UNDO_RESERVE],
						'href' => $this->getUrlToNewDocumentDetail(StoreDocumentTable::TYPE_UNDO_RESERVE),
					],
					[
						'text' => StoreDocumentTable::getTypeList(true)[StoreDocumentTable::TYPE_RETURN],
						'href' => $this->getUrlToNewDocumentDetail(StoreDocumentTable::TYPE_RETURN),
					],
				]
			]);
		}
		else
		{
			if ($this->mode === self::ARRIVAL_MODE)
			{
				if ($this->isFirstTime())
				{
					$addDocumentButton->setLink($this->getUrlToNewDocumentDetail(StoreDocumentTable::TYPE_STORE_ADJUSTMENT, 'Y'));
				}
				else
				{
					$addDocumentButton->setLink($this->getUrlToNewDocumentDetail(StoreDocumentTable::TYPE_ARRIVAL));
				}
			}
			if ($this->mode === self::MOVING_MODE)
			{
				$addDocumentButton->setLink($this->getUrlToNewDocumentDetail(StoreDocumentTable::TYPE_MOVING));
			}
			if ($this->mode === self::DEDUCT_MODE)
			{
				$addDocumentButton->setLink($this->getUrlToNewDocumentDetail(StoreDocumentTable::TYPE_DEDUCT));
			}
		}

		return $addDocumentButton;
	}

	private function getUrlToNewDocumentDetail(string $documentType, bool $isFirstTime = false): string
	{
		if ($isFirstTime)
		{
			$uriEntity = new Uri($this->getUrlToDocumentDetail(0, $documentType, 'Y'));
		}
		else
		{
			$uriEntity = new Uri($this->getUrlToDocumentDetail(0, $documentType));
		}

		$uriEntity->addParams(['focusedTab' => 'tab_products']);

		return $uriEntity->getUri();
	}

	private function getSettingsButtonMenuItems(): array
	{
		$fieldsSettingsItem = [
			'text' => Loc::getMessage('DOCUMENT_LIST_FIELDS_SETTINGS'),
		];
		if ($this->mode === self::ARRIVAL_MODE)
		{
			$fieldsSettingsItem['items'] = [
				[
					'text' => Loc::getMessage('DOCUMENT_LIST_DOC_TYPE_A'),
					'href' => $this->getUserFieldListConfigUrl(StoreDocumentArrivalTable::getUfId()),
					'onclick' => new \Bitrix\UI\Buttons\JsHandler('BX.Catalog.DocumentGridManager.openUfSlider'),
				],
				[
					'text' => Loc::getMessage('DOCUMENT_LIST_DOC_TYPE_S'),
					'href' => $this->getUserFieldListConfigUrl(StoreDocumentStoreAdjustmentTable::getUfId()),
					'onclick' => new \Bitrix\UI\Buttons\JsHandler('BX.Catalog.DocumentGridManager.openUfSlider'),
				],
			];
		}
		else
		{
			$entityId = '';
			if ($this->mode === self::MOVING_MODE)
			{
				$entityId = StoreDocumentMovingTable::getUfId();
			}
			elseif ($this->mode === self::DEDUCT_MODE)
			{
				$entityId = StoreDocumentDeductTable::getUfId();
			}

			if ($entityId)
			{
				$fieldsSettingsItem['href'] = $this->getUserFieldListConfigUrl($entityId);
				$fieldsSettingsItem['onclick'] = new \Bitrix\UI\Buttons\JsHandler('BX.Catalog.DocumentGridManager.openUfSlider');
			}
		}

		return [$fieldsSettingsItem];
	}

	private function getUserFieldListConfigUrl(string $entityId): string
	{
		$url = new Uri($this->arParams['PATH_TO']['UF']);
		$url->addParams(['entityId' => $entityId]);

		return $url->getUri();
	}

	private function isFirstTime(): bool
	{
		static $doIncomeDocsExist = null;

		if ($doIncomeDocsExist === null)
		{
			$doIncomeDocsExist = (bool)StoreDocumentTable::getList([
				'select' => ['ID'],
				'filter' => [
					'=DOC_TYPE' => [StoreDocumentTable::TYPE_ARRIVAL, StoreDocumentTable::TYPE_STORE_ADJUSTMENT],
				],
				'limit' => 1,
			])->fetch();
		}

		return !$doIncomeDocsExist;
	}

	private function isShowGuide(): bool
	{
		$documentListUserOptions = CUserOptions::GetOption('catalog', 'document-list', []);
		$isGuideOver = $documentListUserOptions['isDocumentCreateGuideOver'] ?? false;
		if (is_string($isGuideOver))
		{
			$isGuideOver = filter_var($isGuideOver, FILTER_VALIDATE_BOOLEAN);
		}

		$canModifyAdjustDocument = AccessController::getCurrent()->checkByValue(
			ActionDictionary::ACTION_STORE_DOCUMENT_MODIFY,
			StoreDocumentTable::TYPE_STORE_ADJUSTMENT
		);

		return (
			$this->mode === self::ARRIVAL_MODE
			&& !$isGuideOver
			&& $this->isFirstTime()
			&& Catalog\Component\UseStore::isUsed()
			&& $canModifyAdjustDocument
		);
	}

	private function isShowProductBatchMethodPopup(): bool
	{
		if (Catalog\Config\State::isProductBatchMethodSelected() || !Catalog\Config\State::isEnabledInventoryManagement())
		{
			return false;
		}

		$canUserChangeSettings = $this->accessController->check(ActionDictionary::ACTION_CATALOG_SETTINGS_ACCESS);
		$shouldShowPopupOption = Main\Config\Option::get('catalog', 'should_show_batch_method_onboarding', 'N') === 'Y';
		$userOptions = CUserOptions::GetOption('catalog', 'document-list', []);
		$wasPopupShownForUser = $userOptions['was_batch_method_popup_shown'] ?? 'N' === 'Y';
		// the settings slider is in crm
		$isCrmIncluded = Loader::includeModule('crm');

		return $canUserChangeSettings && $shouldShowPopupOption && !$wasPopupShownForUser && $isCrmIncluded;
	}

	private function isShowProfitReportTour(): bool
	{
		$shouldShowTourOption = Main\Config\Option::get('catalog', 'should_show_batch_method_onboarding', 'N') === 'Y';
		$userOptions = CUserOptions::GetOption('catalog', 'document-list', []);
		$wasTourShownForUser = $userOptions['was_profit_report_tour_shown'] ?? 'N' === 'Y';
		$isInventoryManagementUsed = Catalog\Config\State::isUsedInventoryManagement();

		return !$wasTourShownForUser && $shouldShowTourOption && $isInventoryManagementUsed;
	}

	private function getUserFilter(): array
	{
		$userFilter = $this->filter->getValue();

		foreach ($userFilter as $fieldName => $value)
		{
			if (!$this->checkFieldNameAgainstWhitelist($fieldName))
			{
				unset($userFilter[$fieldName]);
			}
		}

		return $userFilter;
	}

	private function getListFilter()
	{
		$filter = array_merge($this->getUserFilter(), $this->getDocTypeModeFilter());

		$accessFilter = $this->getAccessFilter();
		if ($accessFilter)
		{
			$filter[] = $accessFilter;
		}

		$filter = $this->prepareListFilter($filter);

		return $filter;
	}

	private function prepareListFilter($filter)
	{
		$preparedFilter = $filter;

		if (isset($preparedFilter['STATUS']))
		{
			$statuses = $preparedFilter['STATUS'];
			unset($preparedFilter['STATUS']);

			$statusFilters = [];
			foreach ($statuses as $status)
			{
				$statusFilter = StoreDocumentTable::getOrmFilterByStatus($status);
				if (!empty($statusFilter))
				{
					$statusFilters[] = $statusFilter;
				}
			}
			if (!empty($statusFilters))
			{
				$preparedFilter[] = array_merge(
					[
						'LOGIC' => 'OR',
					],
					$statusFilters
				);
			}
		}

		if (isset($preparedFilter['DOC_NUMBER']))
		{
			$preparedFilter['DOC_NUMBER'] = '%' . $preparedFilter['DOC_NUMBER'] . '%';
		}

		if (Manager::getActiveProvider(Manager::PROVIDER_STORE_DOCUMENT))
		{
			Manager::getActiveProvider(Manager::PROVIDER_STORE_DOCUMENT)::setDocumentsGridFilter($preparedFilter);
		}

		$filterOptions = new \Bitrix\Main\UI\Filter\Options($this->filter->getID());
		$searchString = $filterOptions->getSearchString();
		if ($searchString)
		{
			$preparedFilter['TITLE'] = '%' . $searchString . '%';
		}

		$preparedFilter = $this->prepareUfFilter($preparedFilter);

		return $preparedFilter;
	}

	private function prepareUfFilter(array $filter): array
	{
		if (empty($filter) || $this->mode === self::OTHER_MODE)
		{
			return $filter;
		}

		global $USER_FIELD_MANAGER;
		// field name -> value
		$preparedFilter = $filter;

		$userFieldsInfo = [];
		switch ($this->mode)
		{
			case self::ARRIVAL_MODE:
				$userFieldsInfo = $USER_FIELD_MANAGER->GetUserFields(StoreDocumentArrivalTable::getUfId(), 0, LANGUAGE_ID);
				$userFieldsInfo = array_merge($userFieldsInfo, $USER_FIELD_MANAGER->GetUserFields(StoreDocumentStoreAdjustmentTable::getUfId(), 0, LANGUAGE_ID));
				break;
			case self::MOVING_MODE:
				$userFieldsInfo = $USER_FIELD_MANAGER->GetUserFields(StoreDocumentMovingTable::getUfId(), 0, LANGUAGE_ID);
				break;
			case self::DEDUCT_MODE:
				$userFieldsInfo = $USER_FIELD_MANAGER->GetUserFields(StoreDocumentArrivalTable::getUfId(), 0, LANGUAGE_ID);
				break;
		}
		$userFieldNames = array_keys($userFieldsInfo);

		foreach ($filter as $fieldName => $value)
		{
			if (!in_array($fieldName, $userFieldNames, true))
			{
				continue;
			}

			$userFieldInfo = $userFieldsInfo[$fieldName];
			if ($userFieldInfo['SHOW_FILTER'] === 'I' || $userFieldInfo['USER_TYPE_ID'] === 'enumeration')
			{
				unset($preparedFilter[$fieldName]);
				$preparedFilter['=' . $fieldName] = $value;
			}
			elseif ($userFieldInfo['SHOW_FILTER'] === 'E')
			{
				unset($preparedFilter[$fieldName]);
				$preparedFilter['%' . $fieldName] = $value;
			}
		}

		return $preparedFilter;
	}

	private function getAccessFilter(): ?array
	{
		// default check access
		$isCheckAccess = ($this->arParams['CHECK_ACCESS'] ?? 'Y') === 'Y';
		if (!$isCheckAccess)
		{
			return null;
		}

		$result = [];

		$docTypeFilter = $this->accessController->getEntityFilter(
			ActionDictionary::ACTION_STORE_DOCUMENT_VIEW,
			StoreDocumentTable::class
		);
		if ($docTypeFilter)
		{
			$result[] = $docTypeFilter;
		}

		$storeFilter = $this->accessController->getEntityFilter(
			ActionDictionary::ACTION_STORE_VIEW,
			StoreDocumentTable::class
		);
		if ($storeFilter)
		{
			$result[] = $storeFilter;
		}

		return $result;
	}

	private function getDocTypeModeFilter(): array
	{
		if ($this->mode === self::OTHER_MODE)
		{
			return ['=DOC_TYPE' => [
				StoreDocumentTable::TYPE_RETURN,
				StoreDocumentTable::TYPE_UNDO_RESERVE,
			]];
		}

		return [];
	}

	private function getUrlToDocumentDetail($documentId, $documentType = null, $firstTime = null): string
	{
		if ($this->mode === self::OTHER_MODE)
		{
			if ($documentType)
			{
				$pathToDocumentDetail =
					'/shop/settings/cat_store_document_edit.php?DOCUMENT_TYPE='
					. $documentType
					. '&publicSidePanel=Y&IFRAME=Y&IFRAME_TYPE=SIDE_SLIDER'
				;
			}
			else
			{
				$pathToDocumentDetail =
					'/shop/settings/cat_store_document_edit.php?publicSidePanel=Y&IFRAME=Y&IFRAME_TYPE=SIDE_SLIDER&ID='
					. $documentId
				;
			}

			return InventoryManagementSourceBuilder::getInstance()->addInventoryManagementSourceParam($pathToDocumentDetail);
		}

		$pathToDocumentDetailTemplate = $this->arParams['PATH_TO']['DOCUMENT'] ?? '';
		if ($pathToDocumentDetailTemplate === '')
		{
			return $pathToDocumentDetailTemplate;
		}

		$pathToDocumentDetail = str_replace('#DOCUMENT_ID#', $documentId, $pathToDocumentDetailTemplate);

		if ($documentType)
		{
			$pathToDocumentDetail .= '?DOCUMENT_TYPE=' . $documentType;
			if ($firstTime)
			{
				$pathToDocumentDetail .= '&firstTime=' . $firstTime;
			}
		}

		return InventoryManagementSourceBuilder::getInstance()->addInventoryManagementSourceParam($pathToDocumentDetail);
	}

	private function isUserFilterApplied(): bool
	{
		return !empty($this->getUserFilter());
	}

	private function initInventoryManagementSlider()
	{
		$context = Main\Application::getInstance()->getContext();
		/** @var \Bitrix\Main\HttpRequest $request */
		$request = $context->getRequest();

		$this->arResult['OPEN_INVENTORY_MANAGEMENT_SLIDER'] =
			Catalog\Component\UseStore::needShowSlider()
			&& $request->get(Catalog\Component\UseStore::URL_PARAM_STORE_MASTER_HIDE) !== 'Y'
		;
		$this->arResult['OPEN_INVENTORY_MANAGEMENT_SLIDER_ON_ACTION'] = !Catalog\Component\UseStore::isUsed();

		$sliderPath = \CComponentEngine::makeComponentPath('bitrix:catalog.warehouse.master.clear');
		$sliderPath = getLocalPath('components' . $sliderPath . '/slider.php');
		if ($this->arResult['INVENTORY_MANAGEMENT_SOURCE'])
		{
			$sliderPath .= '?inventoryManagementSource=' . $this->arResult['INVENTORY_MANAGEMENT_SOURCE'];
		}
		$this->arResult['MASTER_SLIDER_URL'] = $sliderPath;
	}

	private function getStubLogoList()
	{
		$quickbooksIconPath = $this->getPath() . '/images/document-list-quickbooks.png';
		$zohoIconPath = $this->getPath() . '/images/document-list-zoho.png';

		$logoList = '
		<div class="catalog-store-document-stub-transfer-info-systems-item">
			<img src="' . $zohoIconPath . '" alt="Zoho Inventory">
		</div>
		<div class="catalog-store-document-stub-transfer-info-systems-item">
			<img src="' . $quickbooksIconPath . '" alt="QuickBooks">
		</div>
		';

		if (in_array($this->getZone(), ['ru', 'kz', 'by']))
		{
			$mystoreIconPath = $this->getPath() . '/images/document-list-mystore.svg';

			$companyNames = Loc::loadLanguageFile(
				$_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/catalog/regionalsystemfields/companynames.php',
				'ru'
			);
			$logoList .= '
			<div class="catalog-store-document-stub-transfer-info-systems-item">
				<img src="' . $mystoreIconPath . '" alt="' . $companyNames['COMPANY_NAME_MY_STORE'] . '">
			</div>
			';
		}

		return '
			<div class="catalog-store-document-stub-transfer-info-systems">
				' . $logoList . '
				<div class="catalog-store-document-stub-transfer-info-systems-item">
				' . Loc::getMessage('DOCUMENT_LIST_STUB_MIGRATION_MORE') . '
				</div>
			</div>
		';
	}

	private function getZone()
	{
		if (\Bitrix\Main\Loader::includeModule('bitrix24'))
		{
			$zone = \CBitrix24::getPortalZone();
		}
		else
		{
			$iterator = Bitrix\Main\Localization\LanguageTable::getList([
				'select' => ['ID'],
				'filter' => [
					'=DEF' => 'Y',
					'=ACTIVE' => 'Y'
				]
			]);
			$row = $iterator->fetch();
			$zone = $row['ID'];
		}

		return $zone;
	}

	/**
	 * @param array $column
	 * @return string
	 */
	private function getContractorName(array $column): string
	{
		if (Manager::getActiveProvider(Manager::PROVIDER_STORE_DOCUMENT))
		{
			$contractor = Manager::getActiveProvider(Manager::PROVIDER_STORE_DOCUMENT)::getContractorByDocumentId((int)$column['ID']);

			return $contractor ? $contractor->getName() : '';
		}

		$contractorId = (int)$column['CONTRACTOR_ID'];
		$contractors = $this->getContractors();

		if (!isset($contractors[$contractorId]))
		{
			return '';
		}

		return (string)$contractors[$contractorId]['NAME'];
	}
}

Anon7 - 2022
AnonSec Team