403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/cvetdv.ru/bitrix/components/yandex.market/admin.sku.status/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/cvetdv.ru/bitrix/components/yandex.market/admin.sku.status/class.php
<?php
namespace Yandex\Market\Components;

use Bitrix\Main;
use Bitrix\Main\Localization\Loc;
use Bitrix\Iblock;
use Yandex\Market\Utils as MarketUtils;
use Yandex\Market\Api;
use Yandex\Market\Trading\Business;
use Yandex\Market\Trading\Service as TradingService;

Loc::loadMessages(__FILE__);

/** @noinspection PhpUnused */
class AdminSkuStatus extends \CBitrixComponent
{
	const LIMIT_FULL = 50;
	const LIMIT_PRODUCT = 200;

	private static $iblockLimitCache = [];

	public function onPrepareComponentParams($arParams)
	{
		$arParams['IBLOCK_ID'] = (int)$arParams['IBLOCK_ID'];
		$arParams['ELEMENT_ID'] = (int)$arParams['ELEMENT_ID'];

		return $arParams;
	}

	public function executeComponent()
	{
		if ($this->arParams['ELEMENT_ID'] <= 0) { return ''; }

		$this->arResult['LIMIT'] = self::iblockLimit($this->arParams['IBLOCK_ID']);

		$this->includeComponentTemplate();

		return $this->arResult['HTML'];
	}

	private static function iblockLimit($iblockId)
	{
		$iblockId = (int)$iblockId;

		if ($iblockId <= 0 || !Main\Loader::includeModule('catalog'))
		{
			return self::LIMIT_PRODUCT;
		}

		if (!isset(self::$iblockLimitCache[$iblockId]))
		{
			$catalog = \CCatalogSku::GetInfoByIBlock($iblockId);

			self::$iblockLimitCache[$iblockId] = (
				$catalog !== false && defined('CCatalogSku::TYPE_FULL') && $catalog['CATALOG_TYPE'] === \CCatalogSku::TYPE_FULL
					? self::LIMIT_FULL
					: self::LIMIT_PRODUCT
			);
		}

		return self::$iblockLimitCache[$iblockId];
	}

	public function loadAction($iblockId, array $elementIds)
	{
		if (empty($elementIds)) { return []; }

		$this->checkIblockReadAccess($iblockId);

		$businesses = $this->businesses($iblockId);
		$elementStatuses = $this->collectElementStatuses($businesses, $iblockId, $elementIds);
		$elementStatuses = $this->calculateAverageRating($elementStatuses);

		return [
			'businesses' => $this->compileBusinessPayload($businesses),
			'elements' => $elementStatuses,
		];
	}

	private function checkIblockReadAccess($iblockId)
	{
		if (
			!Main\Loader::includeModule('iblock')
			|| !\CIBlockRights::UserHasRightTo($iblockId, $iblockId, "iblock_admin_display")
		)
		{
			throw new Main\AccessDeniedException(Loc::getMessage('YANDEX_MARKET_SKU_STATUS_READ_ACCESS_DENIED'));
		}
	}

	private function businesses($iblockId)
	{
		$businesses = [];

		foreach (Business\Model::loadList() as $business)
		{
			if (!$this->canUseSkuMapForIblock($business, $iblockId) || !$this->isActiveBusiness($business)) { continue; }

			$businesses[] = $business;
		}

		return $businesses;
	}

	private function mapElementIdsToOfferIds($iblockId, array $elementIds)
	{
		if (empty($elementIds) || !Main\Loader::includeModule('catalog'))
		{
			return array_combine($elementIds, $elementIds);
		}

		$catalog = \CCatalogSku::GetInfoByIBlock($iblockId);

		if (
			$catalog === false
			|| !defined('CCatalogSku::TYPE_FULL')
			|| $catalog['CATALOG_TYPE'] !== \CCatalogSku::TYPE_FULL
			|| empty($catalog['SKU_PROPERTY_ID'])
			|| !Main\Loader::includeModule('iblock')
		)
		{
			return array_combine($elementIds, $elementIds);
		}

		$parents = array_fill_keys($elementIds, true);
		$offerMap = [];

		foreach (array_chunk($elementIds, 500) as $elementsChunk)
		{
			$query = \CIBlockElement::GetPropertyValues(
				$catalog['IBLOCK_ID'],
				[ '=PROPERTY_' . $catalog['SKU_PROPERTY_ID'] => $elementsChunk ],
				false,
				[ 'ID' => $catalog['SKU_PROPERTY_ID'] ]
			);

			while ($propertyRow = $query->Fetch())
			{
				$offerId = (int)$propertyRow['IBLOCK_ELEMENT_ID'];
				$parentId = (int)$propertyRow[$catalog['SKU_PROPERTY_ID']];

				if (!isset($parents[$parentId])) { continue; }

				$parents[$parentId] = false;
				$offerMap[$offerId] = $parentId;
			}
		}

		$standaloneParents = array_keys(array_filter($parents));

		return $offerMap + array_combine($standaloneParents, $standaloneParents);
	}

	private function collectElementStatuses(array $businesses, $iblockId, $elementIds)
	{
		$offerMap = $this->mapElementIdsToOfferIds($iblockId, $elementIds);
		$result = $this->skeletonElementStatuses($elementIds);

		/** @var Business\Model $business */
		foreach ($businesses as $business)
		{
			try
			{
				$skuMap = $this->mapOfferIdsToSku($business, array_keys($offerMap));
				$skuMap = $this->limitSkuCount($skuMap, $offerMap);
				$skuStatuses = $this->fetchSkuStatuses($business, array_values($skuMap));
				$skuStatuses = $this->fulfilSkuName($skuStatuses, $skuMap);

				$result = $this->combineElementStatuses($business, $skuStatuses, $skuMap, $offerMap, $result);
				$result = $this->groupElementStatusesOffers($result);
			}
			catch (\Exception $exception)
			{
				if (!($exception instanceof Main\SystemException))
				{
					Main\Application::getInstance()->getExceptionHandler()->writeToLog($exception);
				}

				$result = $this->writeElementStatusesError($business, $elementIds, $exception->getMessage(), $result);
			}
				/** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */
			catch (\Throwable $exception)
			{
				Main\Application::getInstance()->getExceptionHandler()->writeToLog($exception);

				$result = $this->writeElementStatusesError($business, $elementIds, $exception->getMessage(), $result);
			}
		}

		return $result;
	}

	private function skeletonElementStatuses(array $elementIds)
	{
		$result = [];

		foreach ($elementIds as $elementId)
		{
			$result[$elementId] = [
				'rating' => null,
				'businesses' => [],
			];
		}

		return $result;
	}

	private function isActiveBusiness(Business\Model $business)
	{
		if ($business->getTradingCollection()->getActive() !== null)
		{
			return true;
		}

		$catalog = $business->getCatalog();

		return ($catalog !== null && $catalog->wasSubmitted() && $catalog->isActive());
	}

	private function canUseSkuMapForIblock(Business\Model $business, $iblockId)
	{
		$iblockIds = $business->getOptions()->getSkuMap()->getIblockIds();

		if (empty($iblockIds) || in_array($iblockId, $iblockIds, true)) { return true; }

		if (!Main\Loader::includeModule('catalog')) { return false; }

		$catalog = \CCatalogSku::GetInfoByIBlock($iblockId);

		if ($catalog === false) { return false; }

		return (
			in_array((int)$catalog['IBLOCK_ID'], $iblockIds, true)
			|| (
				!empty($catalog['PRODUCT_IBLOCK_ID'])
				&& in_array((int)$catalog['PRODUCT_IBLOCK_ID'], $iblockIds, true)
			)
		);
	}

	private function mapOfferIdsToSku(Business\Model $business, array $offerIds)
	{
		if (empty($offerIds)) { return []; }

		/** @var TradingService\Common\Command\SkuMap $command */
		$trading = $business->getPrimaryTrading();
		$command = $trading->wakeupService()->getContainer()->get(TradingService\Common\Command\SkuMap::class, [
			'environment' => $trading->getEnvironment(),
		]);
		$skuMap = $command->make($offerIds);

		if ($skuMap === null)
		{
			return array_combine($offerIds, $offerIds);
		}

		return $skuMap;
	}

	private function limitSkuCount(array $skuMap, array $offerMap)
	{
		$limit = Api\Business\OfferCards\Request::OFFER_IDS_LIMIT;
		$overhead = count($skuMap) - $limit;

		if ($overhead <= 0) { return $skuMap; }

		$groups = [];

		foreach ($skuMap as $offerId => $sku)
		{
			$elementId = $offerMap[$offerId];

			if (!isset($groups[$elementId]))
			{
				$groups[$elementId] = [];
			}

			$groups[$elementId][] = $offerId;
		}

		$groupsCount = count($groups);

		if ($groupsCount === 0) { return $skuMap; }

		$elementLimit = max(1, floor($limit / $groupsCount));

		do
		{
			$hasHugeGroup = false;

			foreach ($groups as &$group)
			{
				if (count($group) <= $elementLimit) { continue; }

				$hasHugeGroup = true;
				$offerId = array_pop($group);

				unset($skuMap[$offerId]);

				if (--$overhead <= 0) { break; }
			}
			unset($group);
		}
		while ($overhead > 0 && $hasHugeGroup);

		return $skuMap;
	}

	private function fetchSkuStatuses(Business\Model $business, array $skus)
	{
		$skuStatuses = [];

		foreach (array_chunk($skus, Api\Business\OfferCards\Request::OFFER_IDS_LIMIT) as $skusChunk)
		{
			$request = new Api\Business\OfferCards\Request($business->getId(), $business->getOptions()->getApiAuth(), $business->createLogger());
			$request->setOfferIds($skusChunk);

			/** @var Api\Business\OfferCards\OfferCard $offerCard */
			foreach ($request->execute()->getOfferCards() as $offerCard)
			{
				$messageGroups = $offerCard->groupMessages();
				$messageGroups = $this->uniqueMessages($messageGroups);

				$skuStatuses[] = [
					'sku' => $offerCard->getOfferId(),
					'name' => $offerCard->getMapping()->getMarketSkuName(),
					'rating' => $offerCard->getContentRating(),
					'caption' => $this->captionMessages($messageGroups),
					'messages' => $messageGroups,
					'messagesHash' => $this->hashMessages($messageGroups),
				];
			}
		}

		return $skuStatuses;
	}

	private function uniqueMessages(array $messageGroups)
	{
		foreach ($messageGroups as &$messageGroup)
		{
			$unique = [];
			$changed = false;

			foreach ($messageGroup as $messageKey => $message)
			{
				$text = ($message['comment'] ?: $message['message']);

				if (isset($unique[$text]))
				{
					$changed = true;
					unset($messageGroup[$messageKey]);
					continue;
				}

				$unique[$text] = true;
			}

			if ($changed)
			{
				$messageGroup = array_values($messageGroup);
			}
		}
		unset($messageGroup);

		return $messageGroups;
	}

	private function hashMessages(array $groups)
	{
		$partials = [];

		foreach ($groups as $type => $group)
		{
			foreach ($group as $message)
			{
				$partials[] = $type . ':' . ($message['comment'] ?: $message['message']);
			}
		}

		$partials = array_unique($partials);
		sort($partials);

		$text = strip_tags(implode(PHP_EOL, $partials));
		$text = preg_replace('/\(SKU: .*?\)/', '', $text);

		return md5($text);
	}

	private function captionMessages(array $groups)
	{
		$caption = null;
		$morePartials = [];

		foreach ($groups as $type => $messages)
		{
			if ($caption === null)
			{
				$message = array_shift($messages);

				if ($message === null) { continue; }

				$caption = $message['message'] ?: $message['comment'];
			}

			$messagesCount = count($messages);

			if ($messagesCount === 0) { continue; }

			$typeUpper = mb_strtoupper($type);
			$typeTitle = MarketUtils::sklon($messagesCount, [
				Loc::getMessage('YANDEX_MARKET_SKU_STATUS_' . $typeUpper . '_1'),
				Loc::getMessage('YANDEX_MARKET_SKU_STATUS_' . $typeUpper . '_2'),
				Loc::getMessage('YANDEX_MARKET_SKU_STATUS_' . $typeUpper . '_5'),
			]);

			$morePartials[] = $messagesCount . '&nbsp;' . mb_strtolower($typeTitle);
		}

		if ($caption === null) { return null; }

		return [
			'text' => $caption,
			'more' => $this->mergeCaptionMorePartials($morePartials),
		];
	}

	private function mergeCaptionMorePartials(array $morePartials)
	{
		if (empty($morePartials)) { return ''; }

		if (count($morePartials) === 1)
		{
			return Loc::getMessage('YANDEX_MARKET_SKU_STATUS_AND') . ' ' . $morePartials[0];
		}

		$lastMore = array_pop($morePartials);

		return (
			Loc::getMessage('YANDEX_MARKET_SKU_STATUS_MORE') . ' '
			. implode(', ', $morePartials)
			. ' ' . Loc::getMessage('YANDEX_MARKET_SKU_STATUS_AND') . ' '
			. $lastMore
		);
	}

	private function fulfilSkuName(array $skuStatuses, array $skuMap)
	{
		$skusWithoutName = array_column(array_filter(
			$skuStatuses,
			static function(array $skuStatus) { return ((string)$skuStatus['name'] === ''); }
		), 'sku');
		$skuMap = array_intersect($skuMap, $skusWithoutName);

		if (empty($skuMap) || !Main\Loader::includeModule('iblock')) { return $skuStatuses; }

		$query = Iblock\ElementTable::getList([
			'filter' => [ '=ID' => array_keys($skuMap) ],
			'select' => [ 'ID', 'NAME' ],
		]);

		while ($row = $query->fetch())
		{
			if (!isset($skuMap[$row['ID']])) { continue; }

			$sku = (string)$skuMap[$row['ID']];

			foreach ($skuStatuses as &$skuStatus)
			{
				if ($skuStatus['sku'] !== $sku || (string)$skuStatus['name'] !== '') { continue; }

				$skuStatus['name'] = $row['NAME'];
			}
			unset($skuStatus);
		}

		return $skuStatuses;
	}

	private function combineElementStatuses(Business\Model $business, array $skuStatuses, array $skuMap, array $offerMap, array $ready = [])
	{
		$skuToOfferMap = array_flip($skuMap);
		$businessId = $business->getId();

		foreach ($skuStatuses as $skuStatus)
		{
			if (!isset($skuToOfferMap[$skuStatus['sku']])) { continue; }

			$offerId = $skuToOfferMap[$skuStatus['sku']];

			if (!isset($offerMap[$offerId])) { continue; }

			$elementId = $offerMap[$offerId];

			if (!isset($ready[$elementId]['businesses'][$businessId]))
			{
				$ready[$elementId]['businesses'][$businessId] = [
					'rating' => null,
					'offers' => [],
				];
			}

			$ready[$elementId]['businesses'][$businessId]['offers'][] = $skuStatus + [
				'id' => $offerId,
			];
		}

		return $ready;
	}

	private function groupElementStatusesOffers(array $elementStatuses)
	{
		foreach ($elementStatuses as &$elementStatus)
		{
			foreach ($elementStatus['businesses'] as &$businessStatus)
			{
				if (empty($businessStatus['offers'])) { continue; }

				$hashMap = [];
				$changed = false;

				foreach ($businessStatus['offers'] as $offerKey => $offer)
				{
					if (!isset($hashMap[$offer['messagesHash']]))
					{
						$hashMap[$offer['messagesHash']] = $offerKey;
						continue;
					}

					$baseKey = $hashMap[$offer['messagesHash']];
					$baseOffer = &$businessStatus['offers'][$baseKey];

					if (!isset($baseOffer['siblings'])) { $baseOffer['siblings'] = []; }

					$baseOffer['siblings'][] = array_intersect_key($offer, [
						'sku' => true,
						'name' => true,
					]);

					unset($businessStatus['offers'][$offerKey], $baseOffer);
					$changed = true;
				}

				if ($changed)
				{
					$businessStatus['offers'] = array_values($businessStatus['offers']);
				}
			}
			unset($businessStatus);
		}
		unset($elementStatus);

		return $elementStatuses;
	}

	private function writeElementStatusesError(Business\Model $business, array $elementIds, $errorMessage, array $ready)
	{
		$businessId = $business->getId();

		foreach ($elementIds as $elementId)
		{
			$ready[$elementId]['businesses'][$businessId]['error'] = $errorMessage;
		}

		return $ready;
	}

	private function compileBusinessPayload(array $businesses)
	{
		$payload = [];

		/** @var Business\Model $business */
		foreach ($businesses as $business)
		{
			$payload[] = [
				'id' => $business->getId(),
				'name' => $business->getName(),
			];
		}

		return $payload;
	}

	private function calculateAverageRating(array $elementStatuses)
	{
		foreach ($elementStatuses as &$elementStatus)
		{
			$elementRatings = [];

			foreach ($elementStatus['businesses'] as &$businessStatus)
			{
				if (empty($businessStatus['offers'])) { continue; }

				$businessRatings = [];

				foreach ($businessStatus['offers'] as $offer)
				{
					if ($offer['rating'] === null) { continue; }

					$businessRatings[] = $offer['rating'];
					$elementRatings[] = $offer['rating'];
				}

				$businessStatus['rating'] = !empty($businessRatings)
					? floor(array_sum($businessRatings) / count($businessRatings))
					: null;
			}
			unset($businessStatus);

			$elementStatus['rating'] = !empty($elementRatings)
				? floor(array_sum($elementRatings) / count($elementRatings))
				: null;
		}
		unset($elementStatus);

		return $elementStatuses;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit