Your IP : 3.16.135.185


Current Path : /var/www/axolotl/data/www/kirov.axolotls.ru/bitrix/components/bitrix/salescenter.app/
Upload File :
Current File : /var/www/axolotl/data/www/kirov.axolotls.ru/bitrix/components/bitrix/salescenter.app/class.php

<?php

use Bitrix\Main;
use Bitrix\Crm;
use Bitrix\Main\Application;
use Bitrix\Main\PhoneNumber;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Loader;
use Bitrix\Currency\CurrencyManager;
use Bitrix\SalesCenter\Driver;
use Bitrix\SalesCenter\Integration\ImOpenLinesManager;
use Bitrix\SalesCenter\Integration\LandingManager;
use Bitrix\SalesCenter\Integration\PullManager;
use Bitrix\SalesCenter\Integration\SaleManager;
use Bitrix\SalesCenter\Integration\CrmManager;
use Bitrix\SalesCenter\Integration\Bitrix24Manager;
use Bitrix\SalesCenter\Integration\RestManager;
use Bitrix\Sale\Internals\SiteCurrencyTable;
use Bitrix\Sale\PaySystem;
use Bitrix\Sale\Cashbox;
use Bitrix\Sale;
use Bitrix\Main\Engine\Contract\Controllerable;
use Bitrix\Main\Entity\Base;
use Bitrix\Main\Entity\Query;
use Bitrix\Main\Entity\ReferenceField;
use Bitrix\Crm\Timeline\TimelineType;
use Bitrix\Crm\Timeline\Entity\TimelineTable;
use Bitrix\Crm\Timeline\Entity\TimelineBindingTable;
use Bitrix\Rest;

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

class CSalesCenterAppComponent extends CBitrixComponent implements Controllerable
{
	private const TITLE_LENGTH_LIMIT = 50;

	private const LIMIT_COUNT_PAY_SYSTEM = 3;

	/**
	 * @param $arParams
	 * @return array
	 */
	public function onPrepareComponentParams($arParams)
	{
		if(!$arParams['dialogId'])
		{
			$arParams['dialogId'] = $this->request->get('dialogId');
		}

		$arParams['sessionId'] = intval($arParams['sessionId']);
		if(!$arParams['sessionId'])
		{
			$arParams['sessionId'] = intval($this->request->get('sessionId'));
		}

		if(!isset($arParams['disableSendButton']))
		{
			$arParams['disableSendButton'] = ($this->request->get('disableSendButton') === 'y');
		}
		else
		{
			$arParams['disableSendButton'] = (bool)$arParams['disableSendButton'];
		}

		if(!isset($arParams['context']))
		{
			$arParams['context'] = $this->request->get('context');
		}

		if(!isset($arParams['associatedEntityId']))
		{
			$arParams['associatedEntityId'] = $this->request->get('associatedEntityId');
		}

		if(!isset($arParams['associatedEntityTypeId']))
		{
			$arParams['associatedEntityTypeId'] = $this->request->get('associatedEntityTypeId');
		}

		if(!isset($arParams['ownerId']))
		{
			$arParams['ownerId'] = intval($this->request->get('ownerId'));
		}
		if(!isset($arParams['ownerTypeId']))
		{
			$arParams['ownerTypeId'] = $this->request->get('ownerTypeId');
		}

		return parent::onPrepareComponentParams($arParams);
	}

	public function executeComponent()
	{
		if(!\Bitrix\Main\Loader::includeModule("salescenter"))
		{
			ShowError(Loc::getMessage('SALESCENTER_MODULE_ERROR'));
			Application::getInstance()->terminate();
		}

		if(!Driver::getInstance()->isEnabled())
		{
			$this->arResult['isShowFeature'] = true;
			$this->includeComponentTemplate('limit');
			return;
		}

		PullManager::getInstance()->subscribeOnConnect();
		$this->arResult = Driver::getInstance()->getManagerParams();
		$this->arResult['isFrame'] = Application::getInstance()->getContext()->getRequest()->get('IFRAME') === 'Y';
		$this->arResult['isCatalogAvailable'] = (\Bitrix\Main\Config\Option::get('salescenter', 'is_catalog_enabled', 'N') === 'Y');
		$this->arResult['dialogId'] = $this->arParams['dialogId'];
		$this->arResult['sessionId'] = $this->arParams['sessionId'];
		$this->arResult['context'] = $this->arParams['context'];
		$this->arResult['associatedEntityId'] = $this->arParams['associatedEntityId'];
		$this->arResult['associatedEntityTypeId'] = $this->arParams['associatedEntityTypeId'];
		$this->arResult['orderAddPullTag'] = PullManager::getInstance()->subscribeOnOrderAdd();
		$this->arResult['landingUnPublicationPullTag'] = PullManager::getInstance()->subscribeOnLandingUnPublication();
		$this->arResult['landingPublicationPullTag'] = PullManager::getInstance()->subscribeOnLandingPublication();
		$this->arResult['isOrderPublicUrlExists'] = (LandingManager::getInstance()->isOrderPublicUrlExists());
		$this->arResult['isOrderPublicUrlAvailable'] = (LandingManager::getInstance()->isOrderPublicUrlAvailable());
		$this->arResult['orderPublicUrl'] = Main\Engine\UrlManager::getInstance()->getHostUrl().'/';
		$this->arResult['disableSendButton'] = $this->arParams['disableSendButton'];
		$this->arResult['ownerTypeId'] = $this->arParams['ownerTypeId'];
		$this->arResult['ownerId'] = $this->arParams['ownerId'];
		$this->arResult['isApplePayAvailable'] = false;
		$this->arResult['isPaymentsLimitReached'] = Bitrix24Manager::getInstance()->isPaymentsLimitReached();
		$this->arResult['urlSettingsCompanyContacts'] = $this->getComponentSliderPath('bitrix:salescenter.company.contacts');
		$this->arResult['urlSettingsSmsSenders'] = $this->getUrlSmsProviderSetting();

		if (
			Loader::includeModule('crm')
			&& $this->arParams['context'] === 'deal'
		)
		{
			if ((int)$this->arParams['ownerTypeId'] === CCrmOwnerType::Deal)
			{
				$deal = CCrmDeal::GetByID($this->arParams['ownerId']);
				if (!$deal)
				{
					ShowError(Loc::getMessage('SALESCENTER_ERROR_DEAL_NO_FOUND'));
					Application::getInstance()->terminate();
				}

				$this->arResult['sendingMethod'] = 'sms';
				$this->arResult['sendingMethodDesc'] = $this->getSendingMethodDescByType($this->arResult['sendingMethod']);

				$stageId = CrmManager::getInstance()->getStageWithOrderPaidTrigger(
					$this->arParams['ownerId']
				);
				$this->arResult['stageOnOrderPaid'] = $stageId;
				$this->arResult['dealStageList'] = $this->getDealStageList($deal['CATEGORY_ID'], $stageId);

				$this->arResult['contactBlock'] = $this->getContactBlockInfo($deal);
				$this->arResult['contactPhone'] = $this->getDealContactPhoneFormat($deal['ID']);
				$this->arResult['title'] = Loc::getMessage('SALESCENTER_APP_PAY_TITLE');

				if((int)$this->arResult['associatedEntityTypeId'] === CCrmOwnerType::Order)
				{
					$this->arResult['basket'] = $this->getOrderProducts((int)$this->arResult['associatedEntityId']);
					$this->arResult['timeline'] = $this->getOrderTimeline((int)$this->arResult['associatedEntityId']);
				}
				elseif (!$this->hasBindingOrders($deal['ID']))
				{
					$this->arResult['basket'] = $this->getDealProducts($deal['ID']);
				}

				if (
					!isset($this->arResult['timeline'])
					|| count($this->arResult['timeline']) === 0
				)
				{
					$this->arResult['timeline'] = $this->getDefaultTimeline();
				}

				$this->arResult['paySystemList'] = $this->getPaySystemList();
				$this->arResult['deliveryList'] = $this->getDeliveryList();

				$this->arResult['cashboxList'] = [];
				if (Driver::getInstance()->isCashboxEnabled())
				{
					$this->arResult['cashboxList'] = $this->getCashboxList();
				}

				$this->arResult['isAutomationAvailable'] = Crm\Automation\Factory::isAutomationAvailable(\CCrmOwnerType::Deal);
			}
		}

		if($this->arResult['sessionId'] > 0)
		{
			$sessionInfo = ImOpenLinesManager::getInstance()->setSessionId($this->arResult['sessionId'])->getSessionInfo();
			if($sessionInfo)
			{
				$this->arResult['connector'] = $sessionInfo['SOURCE'];
				$this->arResult['lineId'] = $sessionInfo['CONFIG_ID'];
			}
		}

		if (Loader::includeModule('sale')
			&& Loader::includeModule('currency')
			&& Loader::includeModule('catalog')
		)
		{
			$this->arResult['orderCreationOption'] = 'order_creation';
			$this->arResult['paySystemBannerOptionName'] = 'hide_paysystem_banner';
			$this->arResult['showPaySystemSettingBanner'] = true;

			$baseCurrency = SiteCurrencyTable::getSiteCurrency(SITE_ID);
			if (empty($baseCurrency))
			{
				$baseCurrency = CurrencyManager::getBaseCurrency();
			}
			$this->arResult['currencyCode'] = $baseCurrency;
			$currencyDescription = \CCurrencyLang::GetFormatDescription($baseCurrency);
			$this->arResult['CURRENCIES'][] = [
				'CURRENCY' => $currencyDescription['CURRENCY'],
				'FORMAT' => [
					'FORMAT_STRING' => $currencyDescription['FORMAT_STRING'],
					'DEC_POINT' => $currencyDescription['DEC_POINT'],
					'THOUSANDS_SEP' => $currencyDescription['THOUSANDS_SEP'],
					'DECIMALS' => $currencyDescription['DECIMALS'],
					'THOUSANDS_VARIANT' => $currencyDescription['THOUSANDS_VARIANT'],
					'HIDE_ZERO' => $currencyDescription['HIDE_ZERO']
				]
			];

			$this->arResult['currencySymbol'] = \CCrmCurrency::GetCurrencyText($baseCurrency);

			$dbMeasureResult = \CCatalogMeasure::getList(
				array('CODE' => 'ASC'),
				array(),
				false,
				array('nTopCount' => 100),
				array('CODE', 'SYMBOL_RUS', 'SYMBOL_INTL', 'IS_DEFAULT')
			);

			$this->arResult['measures'] = [];
			while($measureFields = $dbMeasureResult->Fetch())
			{
				$this->arResult['measures'][] = [
					'CODE' => intval($measureFields['CODE']),
					'IS_DEFAULT' => $measureFields['IS_DEFAULT'],
					'SYMBOL' => isset($measureFields['SYMBOL_RUS'])
						? $measureFields['SYMBOL_RUS'] : $measureFields['SYMBOL_INTL']
				];
			}

			$this->arResult['showPaySystemSettingBanner'] = $this->needShowPaySystemSettingBanner();
			$options = \CUserOptions::GetOption('salescenter', $this->arResult['orderCreationOption'], array());
			if ($this->arResult['showPaySystemSettingBanner'])
			{
				$options = \CUserOptions::GetOption('salescenter', $this->arResult['orderCreationOption'], []);
				$this->arResult['showPaySystemSettingBanner'] = ($options[$this->arResult['paySystemBannerOptionName']] !== 'Y');
			}

			$paySystemList = PaySystem\Manager::getList([
				'select' => ['ID', 'NAME', 'ACTION_FILE', 'PS_MODE', 'ACTIVE'],
				'filter' => [
					'!=ACTION_FILE' => 'inner',
					'ACTIVE' => 'Y'
				],
			]);
			while ($paySystem = $paySystemList->fetch())
			{
				if ($paySystem['ACTION_FILE'] !== 'cash')
				{
					$this->arResult['showPaySystemSettingBanner'] = false;
				}

				if (SaleManager::getInstance()->isApplePayPayment($paySystem))
				{
					$this->arResult['isApplePayAvailable'] = true;
				}
			}
		}

		global $APPLICATION;
		$APPLICATION->SetTitle(Loc::getMessage('SALESCENTER_APP_TITLE'));
		$this->includeComponentTemplate();
	}

	protected function getContactBlockInfo($deal)
	{
		return [
			'title' => Loc::getMessage(
				'SALESCENTER_APP_CONTACT_BLOCK_TITLE_SMS',
				[
					'#PHONE#' => $this->getDealContactPhoneFormat($deal['ID'])
				]
			),
			'manager' => $this->getManagerInfo($deal['ASSIGNED_BY']),
			'smsSenders' => $this->getSmsSenderList()
		];
	}

	protected function getDefaultTimeline()
	{
		$result = [
			[
				'type' => 'sent',
				'disabled' => true,
				'content' => Loc::getMessage('SALESCENTER_TIMELINE_WATCH_CONTENT_DEFAULT'),
			],
			[
				'type' => 'cash',
				'disabled' => true,
				'content' => Loc::getMessage('SALESCENTER_TIMELINE_PAYMENT_TITLE_DEFAULT'),
			],
		];

		if (Driver::getInstance()->isCashboxEnabled())
		{
			$result[] = [
				'type' => 'check-sent',
				'disabled' => true,
				'content' => Loc::getMessage('SALESCENTER_TIMELINE_CHECK_CONTENT_DEFAULT'),
			];
		}

		return $result;
	}

	protected function getSmsSenderList()
	{
		$result = [];
		$restSender = null;

		$senderList = Crm\Integration\SmsManager::getSenderInfoList(true);
		foreach ($senderList as $sender)
		{
			if ($sender['canUse'])
			{
				if ($sender['id'] === 'rest')
				{
					$restSender = $sender;

					continue;
				}

				$result[] = $sender;
			}
		}

		if ($restSender !== null)
		{
			foreach ($restSender['fromList'] as $sender)
			{
				$result[] = $sender;
			}
		}

		return $result;
	}

	public function getSmsSenderListAction()
	{
		$result = [];
		if (Main\Loader::includeModule("salescenter") && Main\Loader::includeModule("crm"))
		{
			$result = $this->getSmsSenderList();
		}
		return $result;
 	}

	/**
	 * @param $orderId
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\LoaderException
	 */
	protected function getOrderProducts($orderId)
	{
		$result = [];

		$registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
		/** @var Sale\Order $orderClass */
		$orderClass = $registry->getOrderClassName();

		/** @var Sale\Order $entity */
		$entity = $orderClass::load($orderId);
		$basket = $entity->getBasket();

		foreach ($basket as $index=>$basketItem)
		{
			$item = $basketItem->getFieldValues();

			$result[] = [
				'productId' => $item['PRODUCT_ID'],
				'code' => $item['PRODUCT_ID'],
				'name' => $item['NAME'],
				'sort' => $index,
				'basePrice' => $item['BASE_PRICE'],
				'module' => 'catalog',
				'isCustomPrice' => 'Y',
				'catalogPrice' => $item['PRICE'],
				'quantity' => (float)$item['QUANTITY'],
				'measureCode' => $item['MEASURE_CODE'],
				'measureName' => $item['MEASURE_NAME'],
				'taxRate' => $item['VAT_RATE'],
				'taxIncluded' => $item['VAT_INCLUDED'],
				'filePropertyEditHtml' => (new \Bitrix\SalesCenter\Controller\Order())->getFilePropertyEditHtml($item['PRODUCT_ID']),
			];
		}

		return $result;
	}

	protected function getOrderTimeline($orderId)
	{
		$items = $this->getTimeLineItemsByFilter([
			'TYPE_ID'=>[
				CCrmOwnerType::Order,
				CCrmOwnerType::OrderCheck
			],
			'ENTITY_ID'=>$orderId,
			'ENTITY_TYPE_ID'=>CCrmOwnerType::Order,
			'ASSOCIATED_ENTITY_TYPE_ID'=>[
				CCrmOwnerType::Order,
				CCrmOwnerType::OrderPayment,
				CCrmOwnerType::OrderCheck
			]
		]);

		return count($items)>0 ? $this->prepareTimeLineItems($items):[];
	}

	/**
	 * @param $categoryId
	 * @param $stageId
	 * @return array
	 */
	protected function getDealStageList($categoryId, $stageId)
	{
		$result = [
			[
				'id' => '',
				'name' => Loc::getMessage('SALESCENTER_AUTOMATION_STEPS_STAY'),
				'color' => '#2fc6f6',
				'selected' => $stageId === '',
			]
		];

		$dealStageList = CCrmViewHelper::GetDealStageInfos($categoryId);
		foreach ($dealStageList as $stage)
		{
			$result[] = [
				'id' => $stage['STATUS_ID'],
				'name' => $stage['NAME'],
				'color' => $stage['COLOR'],
				'selected' => $stage['STATUS_ID'] === $stageId
			];
		}

		return $result;
	}

	/**
	 * @param $userId
	 * @return array
	 */
	protected function getManagerInfo($userId)
	{
		$result = [
			'name' => '',
			'photo' => ''
		];

		$dbRes = \CUser::GetList(
			($by = 'id'),
			($order = 'asc'),
			['ID' => $userId],
			['FIELDS' => ['PERSONAL_PHOTO', 'NAME']]
		);

		if ($user = $dbRes->Fetch())
		{
			$result['name'] = $user['NAME'];

			$fileInfo = \CFile::ResizeImageGet(
				$user['PERSONAL_PHOTO'] ?? '',
				['width' => 63, 'height' => 63],
				BX_RESIZE_IMAGE_EXACT
			);

			if (is_array($fileInfo) && isset($fileInfo['src']))
			{
				$result['photo'] = $fileInfo['src'];
			}
		}

		return $result;
	}

	/**
	 * @param $dealId
	 * @return array
	 */
	protected function getDealProducts($dealId)
	{
		$result = [];

		$productRows = CCrmDeal::LoadProductRows($dealId);
		foreach ($productRows as $index => $product)
		{
			$item = [
				'productId' => $product['PRODUCT_ID'],
				'code' => $product['PRODUCT_ID'],
				'name' => $product['PRODUCT_NAME'],
				'sort' => $index,
				'module' => $product['PRODUCT_ID'] > 0 ? 'catalog' : '',
				'basePrice' => $product['PRICE_BRUTTO'],
				'isCustomPrice' => 'Y',
				'catalogPrice' => $product['PRICE_BRUTTO'],
				'quantity' => $product['QUANTITY'],
				'measureCode' => $product['MEASURE_CODE'],
				'measureName' => $product['MEASURE_NAME'],
				'taxRate' => $product['TAX_RATE'],
				'taxIncluded' => $product['TAX_INCLUDED'],
			];

			$orderController = new \Bitrix\SalesCenter\Controller\Order();
			if ($filePropertyEditHtml = $orderController->getFilePropertyEditHtml($item['PRODUCT_ID']))
			{
				$item['filePropertyEditHtml'] = $filePropertyEditHtml;
			}

			if ((int)$product['DISCOUNT_TYPE_ID'] === \Bitrix\Crm\Discount::PERCENTAGE)
			{
				if ($product['DISCOUNT_RATE'] > 0)
				{
					$item['discountType'] = 'percent';
					$item['discount'] = $product['DISCOUNT_RATE'];
					$item['showDiscount'] = 'Y';
				}
			}
			elseif ((int)$product['DISCOUNT_TYPE_ID'] === \Bitrix\Crm\Discount::MONETARY)
			{
				$item['discountType'] = 'currency';
				$item['discount'] = $product['DISCOUNT_SUM'];
				$item['showDiscount'] = 'Y';
			}

			$result[] = $item;
		}

		return $result;
	}

	/**
	 * @param $dealId
	 * @return string
	 * @throws Main\ArgumentException
	 */
	protected function getDealContactPhoneFormat($dealId)
	{
		$contactList = \Bitrix\Crm\Binding\DealContactTable::getDealBindings($dealId);
		foreach ($contactList as $contact)
		{
			if ($contact['IS_PRIMARY'] !== 'Y')
			{
				continue;
			}

			$phoneList = CCrmFieldMulti::GetEntityFields('CONTACT', $contact['CONTACT_ID'], 'PHONE', true, false);
			foreach ($phoneList as $phone)
			{
				$parser = PhoneNumber\Parser::getInstance();

				return $parser->parse($phone['VALUE'])->format();
			}
		}

		return '';
	}

	protected function hasBindingOrders($dealId)
	{
		$registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);

		/** @var Crm\Order\DealBinding $dealBinding */
		$dealBinding = $registry->get(ENTITY_CRM_ORDER_DEAL_BINDING);

		return (bool)$dealBinding::getList([
			'select' => ['ORDER_ID'],
			'filter' => [
				'=DEAL_ID' => $dealId
			]
		])->fetch();
	}

	/**
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\IO\FileNotFoundException
	 * @throws Main\SystemException
	 */
	protected function getPaySystemList(): array
	{
		$result = [];

		$paySystemPath = $this->getComponentSliderPath('bitrix:salescenter.paysystem');
		$queryParams = [
			'lang' => LANGUAGE_ID,
			'publicSidePanel' => 'Y',
		];

		$paySystemList = SaleManager::getInstance()->getPaySystemList([
			'!=ACTION_FILE' => ['inner', 'cash'],
		]);
		if ($paySystemList)
		{
			$result['isSet'] = true;

			foreach ($paySystemList as $paySystem)
			{
				$queryParams['ID'] = $paySystem['ID'];
				$paySystemPath->addParams($queryParams);

				$result['items'][] = [
					'name' => $paySystem['NAME'],
					'link' => $paySystemPath->getLocator(),
					'type' => 'paysystem',
					'sort' => $paySystem['SORT'],
				];
			}

			Main\Type\Collection::sortByColumn($result['items'], ['sort' => SORT_ASC]);

			$result['paysystemPanel'] = [
				'name' => Loc::getMessage('SALESCENTER_APP_ADD_TITLE'),
				'link' => $this->getComponentSliderPath('bitrix:salescenter.paysystem.panel')->getLocator(),
				'type' => 'panel',
			];

			if (Bitrix24Manager::getInstance()->isEnabled())
			{
				$feedbackPath = $this->getComponentSliderPath('bitrix:salescenter.feedback');
				$queryParams = [
					'lang' => LANGUAGE_ID,
					'feedback_type' => 'paysystem_offer',
				];
				$feedbackPath->addParams($queryParams);

				$result['paysystemForm'] = [
					'name' => Loc::getMessage('SALESCENTER_APP_RECOMMENDATION_TITLE'),
					'link' => $feedbackPath->getLocator(),
					'width' => 735,
					'type' => 'form',
				];
			}
		}
		else
		{
			$paySystemHandlerList = $this->getSliderPaySystemHandlers();
			$handlerList = PaySystem\Manager::getHandlerList();
			$systemHandlers = array_keys($handlerList["SYSTEM"]);
			foreach ($systemHandlers as $key => $systemHandler)
			{
				if (strpos($systemHandler, 'quote_') !== false)
				{
					continue;
				}

				$handlerDescription = PaySystem\Manager::getHandlerDescription($systemHandler);
				if (empty($handlerDescription))
				{
					continue;
				}

				if (!array_key_exists($systemHandler, $paySystemHandlerList))
				{
					continue;
				}

				$img = '/bitrix/components/bitrix/salescenter.paysystem.panel/templates/.default/images/'.$systemHandler;
				$queryParams['ACTION_FILE'] = $systemHandler;

				[$handlerClass] = PaySystem\Manager::includeHandler($systemHandler);
				$psModeList = $handlerClass::getHandlerModeList();
				if ($psModeList)
				{
					foreach (array_keys($psModeList) as $psMode)
					{
						if (!in_array($psMode, $paySystemHandlerList[$systemHandler], true))
						{
							continue;
						}

						$queryParams['PS_MODE'] = $psMode;
						$paySystemPath->addParams($queryParams);

						$result['items'][] = [
							'name' => $handlerDescription['NAME'] ?? $handlerList['SYSTEM'][$systemHandler],
							'img' => $img.'_'.$psMode.'.svg',
							'info' => Loc::getMessage(
								'SALESCENTER_APP_PAYSYSTEM_MODE_INFO',
								[
									'#PAYSYSTEM_NAME#' => $handlerDescription['NAME'],
									'#MODE_NAME#' => $psModeList[$psMode],
								]
							),
							'link' => $paySystemPath->getLocator(),
							'type' => 'paysystem',
							'showTitle' => false,
							'sort' => $this->getPaySystemSort($systemHandler, $psMode),
						];

						if (count($result['items']) >= self::LIMIT_COUNT_PAY_SYSTEM)
						{
							break 2;
						}
					}
				}
				else
				{
					$paySystemPath->addParams($queryParams);

					$result['items'][] = [
						'name' => $handlerDescription['NAME'] ?? $handlerList['SYSTEM'][$systemHandler],
						'img' => $img.'.svg',
						'info' => Loc::getMessage(
							'SALESCENTER_APP_PAYSYSTEM_INFO',
							[
								'#PAYSYSTEM_NAME#' => $handlerDescription['NAME'],
							]
						),
						'link' => $paySystemPath->getLocator(),
						'type' => 'paysystem',
						'showTitle' => false,
						'sort' => $this->getPaySystemSort($systemHandler),
					];

					if (count($result['items']) >= self::LIMIT_COUNT_PAY_SYSTEM)
					{
						break;
					}
				}
			}

			if (RestManager::getInstance()->isEnabled())
			{
				$partnersItems = $this->getPaySystemMarketplaceItems();
				if ($partnersItems)
				{
					$result = array_merge_recursive($result, $partnersItems);
				}
			}

			if ($result['items'])
			{
				Main\Type\Collection::sortByColumn($result['items'], ['sort' => SORT_ASC]);
			}

			$result['isSet'] = false;
			$result['items'][] = [
				'name' => Loc::getMessage('SALESCENTER_APP_PAYSYSTEM_ITEM_EXTRA'),
				'link' => $this->getComponentSliderPath('bitrix:salescenter.paysystem.panel')->getLocator(),
				'type' => 'panel',
			];

			if (Bitrix24Manager::getInstance()->isEnabled())
			{
				$feedbackPath = $this->getComponentSliderPath('bitrix:salescenter.feedback');
				$queryParams = [
					'lang' => LANGUAGE_ID,
					'feedback_type' => 'paysystem_offer',
				];
				$feedbackPath->addParams($queryParams);

				$result['items'][] = [
					'name' => Loc::getMessage('SALESCENTER_APP_OFFER_TITLE'),
					'link' => $feedbackPath->getLocator(),
					'width' => 735,
					'type' => 'form',
				];
			}
		}

		return $result;
	}

	/**
	 * @return array
	 * @throws Main\SystemException
	 */
	private function getPaySystemMarketplaceItems(): array
	{
		$result = [];
		$zone = $this->getZone();
		$installedAppList = $this->getMarketplaceInstalledApps('payment');
		$partnerItems = RestManager::getInstance()->getByTag([
			RestManager::TAG_PAYSYSTEM_PAYMENT,
			RestManager::TAG_PAYSYSTEM_MAKE_PAYMENT,
			$zone
		]);
		$marketplaceItemCodeList = [];
		if (!empty($partnerItems['ITEMS']))
		{
			foreach ($partnerItems['ITEMS'] as $partnerItem)
			{
				$marketplaceItemCodeList[] = $partnerItem['CODE'];
			}
		}

		$marketplaceItemCodeList = array_unique(array_merge(array_keys($installedAppList), $marketplaceItemCodeList));
		foreach($marketplaceItemCodeList as $marketplaceItemCode)
		{
			if ($marketplaceApp = RestManager::getInstance()->getMarketplaceAppByCode($marketplaceItemCode))
			{
				$title = $marketplaceApp['NAME']
					?? $marketplaceApp['LANG'][$zone]['NAME']
					?? current($marketplaceApp['LANG'])['NAME']
					?? '';

				$img = $marketplaceApp['ICON_PRIORITY'];
				if (!$img)
				{
					$img = $marketplaceApp['ICON']
						? $marketplaceApp['ICON']
						: '/bitrix/components/bitrix/salescenter.paysystem.panel/templates/.default/images/marketplace_default.svg';
				}

				$result['items'][] = [
					'id' => (array_key_exists($marketplaceItemCode, $installedAppList)
						? $installedAppList[$marketplaceItemCode]['ID']
						: $marketplaceApp['ID']
					),
					'code' => $marketplaceApp['CODE'],
					'name' => $this->getFormattedTitle($title),
					'img' => $img,
					'installedApp' => array_key_exists($marketplaceItemCode, $installedAppList),
					'info' => $marketplaceApp['SHORT_DESC'],
					'type' => 'marketplace',
					'showTitle' => false,
					'sort' => $marketplaceApp['ID'],
				];
			}
		}

		if ($result['items'])
		{
			Main\Type\Collection::sortByColumn($result['items'], ['sort' => SORT_ASC]);
		}

		return $result;
	}

	/**
	 * @return array
	 * @throws Main\SystemException
	 */
	protected function getDeliveryList(): array
	{
		$result = [];

		if (RestManager::getInstance()->isEnabled())
		{
			$result = $this->getDeliveryMarketplaceItems();
		}

		if (Bitrix24Manager::getInstance()->isEnabled())
		{
			$feedbackPath = $this->getComponentSliderPath('bitrix:salescenter.feedback');
			$queryParams = [
				'lang' => LANGUAGE_ID,
				'feedback_type' => 'delivery_offer',
			];
			$feedbackPath->addParams($queryParams);

			$result['items'][] = [
				'name' => Loc::getMessage('SALESCENTER_APP_RECOMMENDATION_TITLE'),
				'link' => $feedbackPath->getLocator(),
				'width' => 735,
				'type' => 'form',
			];
		}

		return $result;
	}

	/**
	 * @return array
	 * @throws Main\SystemException
	 */
	private function getDeliveryMarketplaceItems(): array
	{
		$result = [];
		$zone = $this->getZone();
		$installedAppList = $this->getMarketplaceInstalledApps('delivery');
		$partnerItems = RestManager::getInstance()->getByTag([
			RestManager::TAG_DELIVERY,
			RestManager::TAG_DELIVERY_MAKE_DELIVERY,
			$zone
		]);
		$marketplaceItemCodeList = [];
		if (!empty($partnerItems['ITEMS']))
		{
			foreach ($partnerItems['ITEMS'] as $partnerItem)
			{
				$marketplaceItemCodeList[] = $partnerItem['CODE'];
			}
		}

		$marketplaceItemCodeList = array_unique(array_merge(array_keys($installedAppList), $marketplaceItemCodeList));
		foreach($marketplaceItemCodeList as $marketplaceItemCode)
		{
			if ($marketplaceApp = RestManager::getInstance()->getMarketplaceAppByCode($marketplaceItemCode))
			{
				$title = $marketplaceApp['NAME']
					?? $marketplaceApp['LANG'][$zone]['NAME']
					?? current($marketplaceApp['LANG'])['NAME']
					?? '';

				$img = $marketplaceApp['ICON_PRIORITY'];
				if (!$img)
				{
					$img = $marketplaceApp['ICON']
						? $marketplaceApp['ICON']
						: '/bitrix/components/bitrix/salescenter.delivery.panel/templates/.default/images/marketplace_default.svg';
				}

				$result['items'][] = [
					'id' => (array_key_exists($marketplaceItemCode, $installedAppList)
						? $installedAppList[$marketplaceItemCode]['ID']
						: $marketplaceApp['ID']
					),
					'code' => $marketplaceApp['CODE'],
					'name' => $this->getFormattedTitle($title),
					'img' => $img,
					'installedApp' => array_key_exists($marketplaceItemCode, $installedAppList),
					'info' => $marketplaceApp['SHORT_DESC'],
					'type' => 'marketplace',
					'showTitle' => ($marketplaceApp['CODE'] === 'integrations24.terminal'),
					'sort' => $marketplaceApp['ID'],
				];
			}
		}

		if ($result['items'])
		{
			Main\Type\Collection::sortByColumn($result['items'], ['sort' => SORT_ASC]);
		}

		return $result;
	}

	/**
	 * @return array
	 * @throws \Bitrix\Main\ArgumentException
	 */
	protected function getCashboxList()
	{
		$result = [];

		$cashboxPath = $this->getComponentSliderPath('bitrix:salescenter.cashbox');
		$queryParams = [
			'lang' => LANGUAGE_ID,
			'publicSidePanel' => 'Y',
		];

		$cashboxList = SaleManager::getInstance()->getCashboxList();
		if ($cashboxList)
		{
			$result['isSet'] = true;

			foreach ($cashboxList as $item)
			{
				$queryParams['id'] = $item['ID'];
				$queryParams['handler'] = $item['HANDLER'];
				$cashboxPath->addParams($queryParams);

				$result['items'][] = [
					'name' => $item['NAME'],
					'link' => $cashboxPath->getLocator(),
				];
			}

			$result['cashboxPanel'] = [
				'name' => Loc::getMessage('SALESCENTER_APP_ADD_TITLE'),
				'link' => $this->getComponentSliderPath('bitrix:salescenter.cashbox.panel')->getLocator(),
			];

			if (Bitrix24Manager::getInstance()->isEnabled())
			{
				$feedbackPath = $this->getComponentSliderPath('bitrix:salescenter.feedback');
				$queryParams = [
					'lang' => LANGUAGE_ID,
					'feedback_type' => 'paysystem_offer',
				];
				$feedbackPath->addParams($queryParams);

				$result['cashboxForm'] = [
					'name' => Loc::getMessage('SALESCENTER_APP_RECOMMENDATION_TITLE'),
					'link' => $feedbackPath->getLocator(),
					'width' => 735,
					'type' => 'form',
				];
			}
		}
		else
		{
			$cashboxHandlers = SaleManager::getCashboxHandlers();
			/** @var Cashbox\Cashbox $cashboxHandler */
			foreach ($cashboxHandlers as $cashboxHandler)
			{
				$queryParams['handler'] = $cashboxHandler;
				$cashboxPath->addParams($queryParams);

				$img = '';
				if (strpos($queryParams['handler'], Cashbox\CashboxAtolFarmV4::class) !== false)
				{
					$img = '/bitrix/components/bitrix/salescenter.cashbox.panel/templates/.default/images/atol.svg';
				}
				elseif (strpos($queryParams['handler'], Cashbox\CashboxOrangeData::class) !== false)
				{
					$img = '/bitrix/components/bitrix/salescenter.cashbox.panel/templates/.default/images/orangedata.svg';
				}

				$name = $cashboxHandler::getName();
				$result['items'][] = [
					'name' => $cashboxHandler::getName(),
					'img' => $img,
					'link' => $cashboxPath->getLocator(),
					'info' => Loc::getMessage(
						'SALESCENTER_APP_CASHBOX_INFO',
						[
							'#CASHBOX_NAME#' => $name,
						]
					),
					'type' => 'cashbox',
					'showTitle' => false,
				];
			}

			$queryParams['handler'] = 'offline';
			$cashboxPath->addParams($queryParams);
			$result['items'][] = [
				'name' => Loc::getMessage('SALESCENTER_APP_CASHBOX_OFFLINE_TITLE'),
				'img' => '/bitrix/components/bitrix/salescenter.cashbox.panel/templates/.default/images/offline.svg',
				'link' => $cashboxPath->getLocator(),
				'info' => Loc::getMessage('SALESCENTER_APP_CASHBOX_OFFLINE_INFO'),
				'type' => 'cashbox',
				'showTitle' => true,
			];

			if (Bitrix24Manager::getInstance()->isEnabled())
			{
				$feedbackPath = $this->getComponentSliderPath('bitrix:salescenter.feedback');
				$queryParams = [
					'lang' => LANGUAGE_ID,
					'feedback_type' => 'paysystem_offer',
				];
				$feedbackPath->addParams($queryParams);

				$result['items'][] = [
					'name' => Loc::getMessage('SALESCENTER_APP_RECOMMENDATION_TITLE'),
					'link' => $feedbackPath->getLocator(),
					'width' => 735,
					'type' => 'form',
				];
			}

			$result['isSet'] = false;
		}

		return $result;
	}

	/**
	 * @return bool
	 * @throws \Bitrix\Main\ArgumentException
	 */
	protected function needShowPaySystemSettingBanner() : bool
	{
		$dbRes = PaySystem\Manager::getList([
			'select' => ['ID', 'NAME', 'ACTION_FILE'],
			'filter' => [
				'!ID' => PaySystem\Manager::getInnerPaySystemId(),
				'!ACTION_FILE' => 'cash',
				'=ACTIVE' => 'Y'
			],
		]);

		return $dbRes->fetch() ? false : true;
	}

	/**
	 * @param $name
	 * @return Main\Web\Uri
	 */
	private function getComponentSliderPath($name): Main\Web\Uri
	{
		$path = \CComponentEngine::makeComponentPath($name);
		$path = getLocalPath('components'.$path.'/slider.php');
		$path = new Main\Web\Uri($path);

		return $path;
	}

	/**
	 * @return array
	 * @throws Main\ArgumentException
	 */
	private function getSliderPaySystemHandlers(): array
	{
		$paySystemList = SaleManager::getSaleshubPaySystemItems();

		$paySystemPanel = [];
		foreach ($paySystemList as $handler => $handlerItem)
		{
			if (!empty($handlerItem['psMode']))
			{
				foreach ($handlerItem['psMode'] as $psMode => $psModeItem)
				{
					if ($psModeItem['slider'])
					{
						$paySystemPanel[$handler][] = $psMode;
					}
				}
			}
			elseif ($handlerItem['slider'])
			{
				$paySystemPanel[$handler] = [];
			}
		}

		return $paySystemPanel;
	}

	/**
	 * @param $handler
	 * @param bool $psMode
	 * @return int|mixed
	 * @throws Main\ArgumentException
	 */
	private function getPaySystemSort($handler, $psMode = false)
	{
		$paySystemList = SaleManager::getSaleshubPaySystemItems();

		$defaultSort = 100;
		if ($psMode)
		{
			return $paySystemList[$handler]['psMode'][$psMode]['sliderSort'] ?? $defaultSort;
		}

		return $paySystemList[$handler]['sliderSort'] ?? $defaultSort;
	}

	/**
	 * @param string $type
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws Main\ArgumentOutOfRangeException
	 * @throws Main\IO\FileNotFoundException
	 * @throws Main\LoaderException
	 * @throws Main\SystemException
	 */
	public function getAjaxDataAction(string $type): array
	{
		$result = [];
		if (Main\Loader::includeModule("salescenter"))
		{
			if ($type === 'PAY_SYSTEM')
			{
				$result = $this->getPaySystemList();
			}
			elseif ($type === 'CASHBOX')
			{
				$result = $this->getCashboxList();
			}
			elseif ($type === 'DELIVERY')
			{
				$result = $this->getDeliveryList();
			}
		}

		return $result;
	}

	/**
	 * @inheritDoc
	 */
	public function configureActions()
	{
		return [];
	}

	protected function prepareTimeLineItemsDateTime($date, $format = 'j F Y H:i')
	{
		$result = '';
		if ($date instanceof \Bitrix\Main\Type\DateTime)
		{
			$result = FormatDate($format, $date->getTimestamp() + CTimeZone::GetOffset());
		}
		return $result;
	}

	protected function prepareTimeLineItems($items)
	{
		$result = [];
		foreach ($items as $item)
		{
			if($item['ASSOCIATED_ENTITY_TYPE_ID'] == CCrmOwnerType::OrderPayment)
			{
				if($item['CHANGED_ENTITY'] == CCrmOwnerType::OrderPaymentName
					&& $item['FIELDS']['ORDER_PAID'] == 'Y')
				{
					$registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
					/** @var Sale\Payment $paymentClassName */
					$paymentClassName = $registry->getPaymentClassName();
					$dbRes = $paymentClassName::getList(array('filter' => array('ID' => $item['ASSOCIATED_ENTITY_ID'])));
					$data = $dbRes->fetch();

					$result[$item['ID']] = [
						'type'=>'payment',
						'sum'=>\CCrmCurrency::MoneyToString($data['SUM'], $data['CURRENCY'], '#'),
						'currency'=>\CCrmCurrency::GetCurrencyText($data['CURRENCY']),
						'content'=>$item['ASSOCIATED_ENTITY']['SUBLEGEND'],
						'title'=>Loc::getMessage('SALESCENTER_TIMELINE_PAYMENT_TITLE',[
							'#DATE_CREATED#'=>$this->prepareTimeLineItemsDateTime($item['CREATED'])
						])
					];
				}
			}
			elseif ($item['ASSOCIATED_ENTITY_TYPE_ID'] == CCrmOwnerType::OrderCheck)
			{
				if($item['TYPE_CATEGORY_ID'] == TimelineType::MARK)
				{
					if(isset($item['SENDED']) && $item['SENDED'] == 'Y')
					{
						$check = \Bitrix\Sale\Cashbox\CheckManager::getObjectById($item['ASSOCIATED_ENTITY_ID']);
						$result[] = [
							'type'=>'check-sent',
							'url'=>(is_null($check) ? '':$check->getUrl()),
							'content'=>Loc::getMessage('SALESCENTER_TIMELINE_CHECKSENT_CONTENT',[
								'#ID#'=>$item['ASSOCIATED_ENTITY_ID'],
								'#DATE_CREATED#'=>$this->prepareTimeLineItemsDateTime($item['CREATED'])
							]),
						];
					}
				}
				elseif($item['TYPE_CATEGORY_ID'] == TimelineType::UNDEFINED)
				{
					$result[] = [
						'type'=>'check',
						'url'=>$item['CHECK_URL'],
						'content'=>Loc::getMessage('SALESCENTER_TIMELINE_CHECK_CONTENT',[
							'#ID#'=>$item['ASSOCIATED_ENTITY_ID'],
							'#DATE_CREATED#'=>$this->prepareTimeLineItemsDateTime($item['CREATED'], 'j F Y')]),
					];
				}
			}
			elseif($item['ASSOCIATED_ENTITY_TYPE_ID'] == CCrmOwnerType::Order)
			{
				if($item['TYPE_CATEGORY_ID'] == TimelineType::MODIFICATION)
				{
					if(isset($item['FIELDS']['VIEWED']) && $item['FIELDS']['VIEWED'] == 'Y')
					{
						$result[] = [
							'type'=>'watch',
							'content'=>Loc::getMessage('SALESCENTER_TIMELINE_WATCH_CONTENT',[
								'#DATE_CREATED#'=>$this->prepareTimeLineItemsDateTime($item['CREATED'])
							]),
						];
					}
					elseif (isset($item['FIELDS']['SENT']) && $item['FIELDS']['SENT'] == 'Y')
					{
						$result[] = [
							'type'=>'sent',
							'url'=>$item['ASSOCIATED_ENTITY']['SHOW_URL'],
							'content'=>Loc::getMessage('SALESCENTER_TIMELINE_SENT_CONTENT',[
								'#DATE_CREATED#'=>$this->prepareTimeLineItemsDateTime($item['CREATED'])
							]),
						];
					}
				}
			}
		}
		return $result;
	}

	protected function getTimeLineItemsByFilter($filter)
	{
		$query = new Query(TimelineTable::getEntity());
		$query->addSelect('*');

		$bindingQuery = new Query(TimelineBindingTable::getEntity());
		$bindingQuery->addSelect('OWNER_ID');
		$bindingQuery->addFilter('=ENTITY_TYPE_ID', $filter['ENTITY_TYPE_ID']);
		$bindingQuery->addFilter('=ENTITY_ID', $filter['ENTITY_ID']);
		$bindingQuery->addSelect('IS_FIXED');
		$query->addSelect('bind.IS_FIXED', 'IS_FIXED');

		$query->registerRuntimeField('',
			new ReferenceField('bind',
				Base::getInstanceByQuery($bindingQuery),
				array('=this.ID' => 'ref.OWNER_ID'),
				array('join_type' => 'INNER')
			)
		);
		$query->whereNotIn(
			'ASSOCIATED_ENTITY_TYPE_ID',
			Crm\Timeline\TimelineManager::getIgnoredEntityTypeIDs()
		);
		$query->addFilter('TYPE_CATEGORY_ID', [TimelineType::CREATION, TimelineType::MODIFICATION, TimelineType::MARK, TimelineType::UNDEFINED]);
		$query->addFilter('TYPE_ID', $filter['TYPE_ID']);
		$query->addFilter('ASSOCIATED_ENTITY_TYPE_ID', $filter['ASSOCIATED_ENTITY_TYPE_ID']);
		$query->setOrder(array('CREATED' => 'ASC', 'ID' => 'ASC'));
		$query->setLimit(10);

		$dbResult = $query->exec();
		$itemIDs = [];
		$items = [];

		while($fields = $dbResult->fetch())
		{
			$itemID = (int)$fields['ID'];
			$items[] = $fields;
			$itemIDs[] = $itemID;
		}

		$itemsMap = array_combine($itemIDs, $items);
		\Bitrix\Crm\Timeline\TimelineManager::prepareDisplayData($itemsMap);
		return array_values($itemsMap);
	}

	protected function getSendingMethodDescByType($type)
	{
		if ($type === 'sms')
		{
			$text = '';
			if (
				(int)$this->arResult['associatedEntityTypeId'] === CCrmOwnerType::Order
				&& $this->arResult['associatedEntityId'] > 0
			)
			{
				$text = $this->getLastSmsMessageByOrderId((int)$this->arResult['associatedEntityId']);
			}

			return [
				'provider' => '',
				'text' => $text <> ''? $text:CrmManager::getInstance()->getSmsTemplate()
			];
		}

		return [];
	}

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

		return $zone;
	}

	/**
	 * @param $title
	 * @return string
	 */
	private function getFormattedTitle($title): string
	{
		if (strlen($title) > self::TITLE_LENGTH_LIMIT)
		{
			$title = substr($title, 0, self::TITLE_LENGTH_LIMIT - 3).'...';
		}

		return $title;
	}

	protected function getUrlSmsProviderSetting()
	{
		$path = \CComponentEngine::makeComponentPath('bitrix:salescenter.smsprovider.panel');
		$path = getLocalPath('components'.$path.'/slider.php');
		$path = new \Bitrix\Main\Web\Uri($path);
		return $path->getLocator();
	}

	protected function getLastSmsMessageByOrderId($orderId = 0)
	{
		$result = '';
		if(intval($orderId)>0)
		{
			if (Loader::includeModule('messageservice'))
			{
				$filter['BINDINGS'][] = [
					'OWNER_ID' => $orderId,
					'OWNER_TYPE_ID' => CCrmOwnerType::Order
				];

				$filter['PROVIDER_ID'] = Bitrix\Crm\Activity\Provider\Sms::getId();
				$filter['PROVIDER_TYPE_ID'] = Bitrix\Crm\Activity\Provider\Sms::getTypeId([]);

				$res = \CCrmActivity::GetList(
					["ID"=>"DESC"],
					$filter,
					false, false,
					[]
				);
				if($row = $res->fetch())
				{
					$id = intval($row['ASSOCIATED_ENTITY_ID']) ?:0;
					$message = $id > 0 ? \Bitrix\MessageService\Message::getFieldsById($id):[];

					$result = isset($message['MESSAGE_BODY']) ? $message['MESSAGE_BODY']:'';
				}
			}
		}

		return $result;
	}

	/**
	 * @param string $category
	 * @return array
	 * @throws Main\ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 */
	private function getMarketplaceInstalledApps(string $category): array
	{
		if(!RestManager::getInstance()->isEnabled())
		{
			return [];
		}

		$marketplaceInstalledApps = [];
		$marketplaceAppCodeList = RestManager::getInstance()->getMarketplaceAppCodeList($category);
		$appIterator = Rest\AppTable::getList([
			'select' => [
				'ID',
				'CODE',
			],
			'filter' => [
				'=CODE' => $marketplaceAppCodeList,
				'=ACTIVE' => 'Y',
			]
		]);
		while ($row = $appIterator->fetch())
		{
			$marketplaceInstalledApps[$row['CODE']] = $row;
		}

		return $marketplaceInstalledApps;
	}

	/**
	 * @param $smsTemplate
	 * @noinspection PhpUnused
	 */
	public function saveSmsTemplateAction($smsTemplate): void
	{
		if (Main\Loader::includeModule("salescenter"))
		{
			$currentSmsTemplate = CrmManager::getInstance()->getSmsTemplate();
			if ($smsTemplate !== $currentSmsTemplate)
			{
				CrmManager::getInstance()->saveSmsTemplate($smsTemplate);
			}
		}
	}
}