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/modules/yandex.market/lib/trading/state/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/cvetdv.ru/bitrix/modules/yandex.market/lib/trading/state/orderstatussync.php
<?php
namespace Yandex\Market\Trading\State;

use Bitrix\Main;
use Yandex\Market;
use Yandex\Market\Trading\Service as TradingService;

class OrderStatusSync extends Internals\AgentSkeleton
{
	use Market\Reference\Concerns\HasMessage;

	const NOTIFY_FORBIDDEN = 'ORDER_PULL_DISABLED';

	protected static $expireDate;

	public static function getDefaultParams()
	{
		return [
			'interval' => static::getPeriod('restart', 86400),
            'sort' => 400, // more priority
		];
	}

	public static function start($campaignId)
	{
		try
		{
			global $pPERIOD;

			$setup = static::getCampaignSetup($campaignId);
			$options = $setup->wakeupService()->getOptions();

			$repeatSync = static::sync($campaignId);

			if ($repeatSync !== false)
			{
				static::register([
					'method' => 'sync',
					'arguments' => is_array($repeatSync) ? $repeatSync : [ $campaignId ],
					'interval' => static::getPeriod('step', static::PERIOD_STEP_DEFAULT),
				]);
			}

			if (
				$options instanceof TradingService\Marketplace\Options
				&& $options->getYandexMode() === TradingService\Marketplace\Options::YANDEX_MODE_PULL
			)
			{
				$pPERIOD = (int)Market\Config::getOption('trading_pull_period', 600);
			}

			return true;
		}
		catch (Main\ObjectNotFoundException $exception)
		{
			return false;
		}
		catch (Main\ObjectPropertyException $exception)
		{
			return false;
		}
	}

	protected static function canRepeat($exception, $errorCount)
	{
		if (static::isRequestForbidden($exception))
		{
			return $errorCount < 1; // only first error skipped
		}

		return parent::canRepeat($exception, $errorCount);
	}

	protected static function isRequestForbidden($exception)
	{
		return (
            $exception instanceof Market\Exceptions\Api\Request
            && in_array($exception->getErrorCode(), ['FORBIDDEN', 'UNAUTHORIZED'], true)
        );
	}

	protected static function logError(Market\Trading\Setup\Model $setup, $message, $arguments = null)
	{
		parent::logError($setup, $message, $arguments);

		if (static::isRequestForbidden($message))
		{
			$switchOffArguments = ($arguments !== null ? array_slice($arguments, 0, 1) : [ $setup->getId() ]);

			static::switchOff($switchOffArguments);
			static::notifySwitchOffMethod($setup, 'FORBIDDEN');
		}
	}

	protected static function notifySwitchOffMethod(Market\Trading\Setup\Model $setup, $reason)
	{
		$tag = static::NOTIFY_FORBIDDEN . '_' . $setup->getId();
		$setupUrl = Market\Ui\Admin\Path::getModuleUrl('trading_edit', [
			'lang' => LANGUAGE_ID,
			'business' => $setup->getBusinessId(),
			'id' => $setup->getId(),
		]);
		$logUrl = Market\Ui\Admin\Path::getModuleUrl('trading_log', [
			'lang' => LANGUAGE_ID,
			'business' => $setup->getBusinessId(),
			'find_level' => Market\Logger\Level::ERROR,
			'find_setup' => $setup->getId(),
			'set_filter' => 'Y',
			'apply_filter' => 'Y',
		]);

		\CAdminNotify::Add([
			'NOTIFY_TYPE' => \CAdminNotify::TYPE_ERROR,
			'MODULE_ID' => Market\Config::getModuleName(),
			'TAG' => $tag,
			'MESSAGE' => self::getMessage($reason, [
				'#SETUP_URL#' => $setupUrl,
				'#LOG_URL#' => $logUrl,
			]),
		]);
	}

	protected static function switchOff(array $arguments = null)
	{
		$methods = [
			'start',
			'sync',
			'fork',
		];

		foreach ($methods as $method)
		{
			static::unregister([
				'method' => $method,
				'arguments' => $arguments,
				'search' => Market\Reference\Agent\Controller::SEARCH_RULE_SOFT,
			]);
		}
	}

	public static function sync($campaignId, $offset = null, $errorCount = 0)
	{
		return static::wrapAction(
			[static::class, 'syncBody'],
			[ $campaignId, $offset ],
			$errorCount
		);
	}

	protected static function syncBody($campaignId, $offset = null)
	{
		$setup = static::getCampaignSetup($campaignId);
		$campaignId = static::castCampaignId($setup, $campaignId);
		$justStarted = ($offset === null);
		$offset = static::sanitizeOffset($campaignId, $offset);
		$dates = static::getSyncDates($offset['start'], $offset['finish']);
		$filter = static::makeDateFilter($dates, $offset['date']);

		if ($filter === null) { return false; }

		$service = $setup->wakeupService();
		$orderCollection = static::loadOrderCollection($service, $filter, $offset['page']);
		$pager = $orderCollection->getPager();
		$hasNext = false;
		$orders = static::mapOrderCollection($orderCollection);
		$accountNumberMap = static::getAccountNumberMap($orders, $setup);
		$first = true;
		$newUpdatedAt = $justStarted ? static::defaultUpdatedAt($offset['start'], $offset['finish']) : null;

		if (isset($offset['order']) && !isset($orders[$offset['order']]))
		{
			unset($offset['order']);
		}

		foreach ($orders as $orderId => $order)
		{
			if (isset($offset['order']))
			{
				if ($offset['order'] !== $orderId) { continue; }

				unset($offset['order']);
			}

			if ($justStarted)
			{
				if ($order instanceof TradingService\Marketplace\Model\Order)
				{
					$orderUpdatedAt = $order->getUpdatedAt();

					if ($newUpdatedAt === null || Market\Data\DateTime::compare($newUpdatedAt, $orderUpdatedAt) === -1)
					{
						$newUpdatedAt = $orderUpdatedAt;
						$newUpdatedAt->add('PT1S');
					}
				}
				else if ($newUpdatedAt === null)
				{
					$newUpdatedAt = clone $offset['start'];
					$newUpdatedAt->add('-PT1S');
				}
			}

			if (!$first && static::isTimeExpired())
			{
				$hasNext = true;
				$offset['order'] = $orderId;
				break;
			}

			$first = false;

			if (!isset($accountNumberMap[$orderId]))
			{
				if (!static::canAccept($setup)) { continue; }
				if (static::isExpired($order) || !static::isNeedOrder($setup, $order)) { continue; }

                $inAcceptInterval = static::isAcceptInterval($order, $offset['finish']);

				if (static::isWaitOrder($order))
				{
                    if ($inAcceptInterval) { continue; }

					static::createFork($campaignId, $orderId, true);
					continue;
				}

                if (!$inAcceptInterval) { continue; }

				$accepted = static::emulateAccept($setup, $order);

				if ($accepted === false)
				{
					static::createFork($campaignId, $orderId);
					continue;
				}

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

				$accountNumberMap[$orderId] = $accepted;
			}

			$updated = static::emulateStatus($setup, $order, $accountNumberMap[$orderId]);

			if ($updated === false)
			{
				static::createFork($campaignId, $orderId);
			}
		}

		if ($newUpdatedAt !== null)
		{
			static::commitUpdatedAt($campaignId, $newUpdatedAt);
		}

		if (!$hasNext && $pager !== null && $pager->hasNext())
		{
			$hasNext = true;

			++$offset['page'];
			$offset = array_diff_key($offset, [ 'order' => true ]);
		}

		if (!$hasNext && count($dates) > $offset['date'] + 1)
		{
			$hasNext = true;

			++$offset['date'];
			$offset['page'] = 1;
			$offset = array_diff_key($offset, [ 'order' => true ]);
		}

		return $hasNext ? [ $campaignId, static::packOffset($offset) ] : false;
	}

	protected static function castCampaignId(Market\Trading\Setup\Model $trading, $campaignId)
	{
		if ($trading->getId() !== (int)$campaignId)
		{
			return $campaignId;
		}

		$tradingCampaignId = $trading->getCampaignId();

		if ($tradingCampaignId > 0)
		{
			return $tradingCampaignId;
		}

		return $campaignId;
	}

	protected static function sanitizeOffset($campaignId, $offset = null)
	{
		$defaults = [
			'start' => new Main\Type\DateTime(),
			'finish' => static::getUpdatedAt($campaignId),
			'date' => 0,
			'page' => 1,
		];

		if ($defaults['finish'] === null)
		{
			$finish = new Main\Type\DateTime();
			$finish->add(sprintf('-P%sD', static::getSyncDaysStep() - 1));

			$defaults['finish'] = $finish;
		}

		if (is_array($offset))
		{
			$offset = static::compatibleOffset($offset);
			$result = static::unpackOffset($offset) + $defaults;
		}
		else if ($offset !== null)
		{
			$result = $defaults;
			$result['page'] = $offset;
		}
		else
		{
			$result = $defaults;
		}

		return $result;
	}

	protected static function compatibleOffset(array $offset)
	{
		if (!isset($offset['start']) || !preg_match('#^\d{4}-\d{2}-\d{2}$#', $offset['start'])) { return $offset; }

		$start = new Main\Type\DateTime($offset['start'], 'Y-m-d');
		$finish = new Main\Type\DateTime();
		$finish->add(sprintf('-P%sD', static::getSyncDaysStep() - 1));

		$offset['start'] = $start->format(\DateTime::ATOM);
		$offset['finish'] = $finish->format(\DateTime::ATOM);

		return $offset;
	}

	protected static function unpackOffset(array $offset)
	{
		$offset['start'] = new Main\Type\DateTime($offset['start'], \DateTime::ATOM);
		$offset['finish'] = new Main\Type\DateTime($offset['finish'], \DateTime::ATOM);

		return $offset;
	}

	protected static function packOffset(array $offset)
	{
		$offset['start'] = $offset['start']->format(\DateTime::ATOM);
		$offset['finish'] = $offset['finish']->format(\DateTime::ATOM);

		return $offset;
	}

	public static function createFork($campaignId, $orderId, $force = false)
	{
		if (!$force && !static::canFork()) { return; }

		$interval = static::getPeriod('timeout', static::PERIOD_TIMEOUT_DEFAULT);
		$nextExec = new Main\Type\DateTime();
		$nextExec->add(sprintf('PT%sS', $interval));

		static::register([
			'method' => 'fork',
			'arguments' => [ $campaignId, $orderId ],
			'interval' => $interval,
			'next_exec' => ConvertTimeStamp($nextExec->getTimestamp(), 'FULL'),
		]);
	}

	/** @noinspection PhpUnused */
	public static function fork($campaignId, $orderId, $repeat = 0, $errorCount = 0)
	{
		return static::wrapAction(
			[static::class, 'forkBody'],
			[ $campaignId, $orderId, $repeat ],
			$errorCount
		);
	}

	protected static function forkBody($campaignId, $orderId, $repeat = 0)
	{
		$setup = static::getCampaignSetup($campaignId);
		$service = $setup->wakeupService();
		$order = static::loadOrder($service, $orderId);

		if (static::isExpired($order) || !static::isNeedOrder($setup, $order)) { return false; }
		if (static::isWaitOrder($order)) { return true; }

		$accepted = static::emulateAccept($setup, $order);

		if ($accepted === null) { return false; }

		if ($accepted !== false)
		{
			$updated = static::emulateStatus($setup, $order, $accepted);

			if ($updated) { return false; }
		}

		++$repeat;

		return $repeat < static::getForkLimit() ? [ $campaignId, $orderId, $repeat ] : false;
	}

	protected static function canFork()
	{
		return static::getForkLimit() > 0;
	}

	protected static function getForkLimit()
	{
		$name = static::optionName('fork_limit');
		$option = (int)Market\Config::getOption($name, 3);

		return max(0, $option);
	}

	protected static function getSyncDates(Main\Type\DateTime $startDate, Main\Type\DateTime $finishDate)
	{
		$days = static::getSyncDaysLimit();
		$step = static::getSyncDaysStep();
		$count = ceil($days / $step);
		$result = [];

		$loopDate = clone $startDate;
		$loopDate->add('P1D'); // fix query over date limit with local timezone

		for ($i = 1; $i <= $count; $i++)
		{
			$loopDate->add(sprintf('-P%sD', $step));

			if ($finishDate->getTimestamp() >= $loopDate->getTimestamp())
			{
				$result[] = clone $finishDate;
				break;
			}

			$result[] = clone $loopDate;
		}

		return $result;
	}

	protected static function getSyncDaysStep()
	{
		$name = static::optionName('days_step');
		$option = (int)Market\Config::getOption($name, 30);

		return max(1, $option);
	}

	protected static function getSyncDaysLimit()
	{
		$name = static::optionName('days_limit');
		$option = (int)Market\Config::getOption($name, 60);

		return max(1, $option);
	}

	protected static function getOptionPrefix()
	{
		return 'trading_status_sync';
	}

	protected static function getPageSize()
	{
		$name = static::optionName('page_size');
		$option = (int)Market\Config::getOption($name, 50);

		return max(1, min(50, $option));
	}

	protected static function makeDateFilter(array $dates, $offset = 0)
	{
		if (!isset($dates[$offset])) { return null; }

		$result = [
			'updatedAtFrom' => $dates[$offset],
		];

		if ($offset > 0)
		{
			$result['updatedAtTo'] = $dates[$offset - 1];
		}

		return $result;
	}

    protected static function defaultUpdatedAt(Main\Type\DateTime $start, Main\Type\DateTime $finish)
    {
        $default = clone $start;
        $default->add('-P1D');

        if (Market\Data\DateTime::compare($default, $finish) !== 1) { return null; }

        return $default;
    }

	protected static function commitUpdatedAt($campaignId, Main\Type\DateTime $newUpdatedAt)
	{
		$lastUpdatedAt = static::getUpdatedAt($campaignId);

		if ($lastUpdatedAt !== null && Market\Data\DateTime::compare($newUpdatedAt, $lastUpdatedAt) !== 1) { return; }

		$name = static::optionName('updated_' . $campaignId);

		Market\State::set($name, $newUpdatedAt->format(\DateTime::ATOM));
	}

	protected static function getUpdatedAt($campaignId)
	{
		$name = static::optionName('updated_' . $campaignId);
		$stored = (string)Market\State::get($name);

		if ($stored === '') { return null; }

		return new Main\Type\DateTime($stored, \DateTime::ATOM);
	}

	protected static function loadOrderCollection(TradingService\Reference\Provider $service, array $filter = [], $page = 0)
	{
		/** @var TradingService\Common\Options $options */
		$options = $service->getOptions();
		$pageSize = static::getPageSize();
		$parameters = [
			'page' => max($page, 1),
			'pageSize' => $pageSize,
		];
		$parameters += $filter;

        if (Market\Config::isDevMode())
        {
            $parameters['fake'] = true;
        }

		$orderFacade = $service->getModelFactory()->getOrderFacadeClassName();

		return $orderFacade::loadList($options, $parameters);
	}

	protected static function loadOrder(TradingService\Reference\Provider $service, $orderId)
	{
		/** @var TradingService\Common\Options $options */
		$options = $service->getOptions();
		$orderFacade = $service->getModelFactory()->getOrderFacadeClassName();

		return $orderFacade::load($options, $orderId);
	}

	protected static function mapOrderCollection(Market\Api\Model\OrderCollection $orderCollection)
	{
		$result = [];

		/** @var Market\Api\Model\Order $order */
		foreach ($orderCollection as $order)
		{
			$result[$order->getId()] = $order;
		}

		return $result;
	}

	protected static function getAccountNumberMap(array $orders, Market\Trading\Setup\Model $setup)
	{
		return $setup->getEnvironment()->getOrderRegistry()->searchList(
			array_keys($orders),
			$setup->getPlatform(),
			false
		);
	}

	protected static function canAccept(Market\Trading\Setup\Model $setup)
	{
		$options = $setup->wakeupService()->getOptions();

		return (
			$options instanceof TradingService\Marketplace\Options
			&& $options->getYandexMode() === TradingService\Marketplace\Options::YANDEX_MODE_PULL
		);
	}

	protected static function isExpired(Market\Api\Model\Order $order)
	{
		$expireDate = static::getExpireDate();
		$createDate = $order->getCreationDate();

		return Market\Data\DateTime::compare($createDate, $expireDate) === -1;
	}

	protected static function getExpireDate()
	{
		if (static::$expireDate === null)
		{
			$expireDays = static::getExpireDays();
			$expireDate = new Main\Type\DateTime();
			$expireDate->add(sprintf('-P%sD', $expireDays));

			static::$expireDate = $expireDate;
		}

		return static::$expireDate;
	}

	protected static function getExpireDays()
	{
		return Internals\DataCleaner::getExpireDays('status');
	}

    protected static function isAcceptInterval(Market\Api\Model\Order $order, Main\Type\DateTime $finish)
    {
        $intervalName = static::optionName('accept_interval');
        $interval = max(1, (int)Market\Config::getOption($intervalName, 6));

        $expire = clone $finish;
        $expire->add(sprintf('-PT%sH', $interval));

        return Market\Data\DateTime::compare($order->getCreationDate(), $expire) !== -1;
    }

	protected static function isNeedOrder(Market\Trading\Setup\Model $setup, Market\Api\Model\Order $order)
	{
		$serviceStatus = $setup->getService()->getStatus();

		if ($serviceStatus->isCanceled($order->getStatus(), $order->getSubStatus()))
		{
			return false;
		}

		if (!($serviceStatus instanceof TradingService\Marketplace\Status)) { return true; }

		if ($serviceStatus->isOrderDelivered($order->getStatus()))
		{
			$expireDate = new Main\Type\DateTime();
			$expireDate->add('-P7D');

			return Market\Data\DateTime::compare($order->getCreationDate(), $expireDate) !== -1;
		}

		return true;
	}

	protected static function isWaitOrder(Market\Api\Model\Order $order)
	{
		if (!($order instanceof TradingService\Marketplace\Model\Order)) { return false; }
		if (!in_array($order->getStatus(), [
			TradingService\Marketplace\Status::STATUS_UNPAID,
			TradingService\Marketplace\Status::STATUS_PLACING,
			TradingService\Marketplace\Status::STATUS_RESERVED,
		], true)) { return false; }

		$buyer = $order->getBuyer();

		return (
			$buyer === null
			|| $buyer->getType() !== TradingService\Marketplace\Model\Order\Buyer::TYPE_BUSINESS
		);
	}

	protected static function emulateAccept(Market\Trading\Setup\Model $setup, Market\Api\Model\Order $order)
	{
		$response = static::emulateAction($setup, $order, 'order/accept');

		if (!isset($response['order'])) { return false; }

		return isset($response['order']['id']) ? $response['order']['id'] : null;
	}

	protected static function emulateStatus(Market\Trading\Setup\Model $setup, Market\Api\Model\Order $order, $accountNumber)
	{
		$response = static::emulateAction($setup, $order, 'order/status', $accountNumber);

		return $response !== null;
	}

	protected static function emulateAction(Market\Trading\Setup\Model $setup, Market\Api\Model\Order $order, $path, $accountNumber = null)
	{
		$logger = null;
		$audit = null;

		try
		{
			$environment = $setup->getEnvironment();
			$service = $setup->wakeupService();
			$logger = $service->getLogger();
			$server = Main\Application::getInstance()->getContext()->getServer();
			$request = static::makeRequestFromOrder($server, $order);

			$action = $service->getRouter()->getHttpAction($path, $environment, $request, $server);
			$audit = $action->getAudit();

			if ($logger instanceof Market\Logger\Trading\Logger)
			{
				$logger->setContext('AUDIT', $audit);
			}

			$action->process();

			$result = $action->getResponse()->getRaw();
		}
		catch (Main\SystemException $exception)
		{
			if ($logger === null) { throw $exception; }

			$logger->error($exception, array_filter([
				'AUDIT' => $audit,
				'ENTITY_TYPE' => Market\Trading\Entity\Registry::ENTITY_TYPE_ORDER,
				'ENTITY_ID' => $accountNumber,
			]));

			$result = null;
		}
		/** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */
		catch (\Throwable $exception)
		{
			if ($logger === null) { throw $exception; }

			$logger->error($exception, array_filter([
				'AUDIT' => $audit,
				'ENTITY_TYPE' => Market\Trading\Entity\Registry::ENTITY_TYPE_ORDER,
				'ENTITY_ID' => $accountNumber,
			]));

			throw $exception;
		}

		return $result;
	}

	protected static function makeRequestFromOrder(Main\Server $server, Market\Api\Model\Order $order)
	{
		return new Main\HttpRequest(
			$server,
			[], // query string
			[
				'order' => $order->getFields(),
				'emulated' => true,
				'download' => true,
			], // post
			[], // files
			[] // cookies
		);
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit