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/rospirotorg.ru/bitrix/modules/sale/lib/rest/synchronization/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/sale/lib/rest/synchronization/synchronizer.php
<?php


namespace Bitrix\Sale\Rest\Synchronization;


use Bitrix\Main\Context;
use Bitrix\Main\Engine\Controller;
use Bitrix\Main\Engine\Response\Converter;
use Bitrix\Main\Error;
use Bitrix\Main\EventResult;
use Bitrix\Main\Localization\Loc;
use Bitrix\Sale\EntityMarker;
use Bitrix\Sale\Order;
use Bitrix\Sale\OrderHistory;
use Bitrix\Sale\OrderTable;
use Bitrix\Sale\Registry;
use Bitrix\Sale\Rest\Externalizer;
use Bitrix\Sale\Rest\Internalizer;
use Bitrix\Sale\Result;

/**
 * Class Synchronizer
 * @package Bitrix\Sale\Rest\Synchronization
 * @intrnal
 */
final class Synchronizer
{
	protected $request;

	const SYNCHRONIZER_MARKER_ERROR = 'SYNCHRONIZER_ERROR';
	const MODE_SAVE = 'save';
	const MODE_DELETE = 'delete';

	public function __construct()
	{
		$this->request = Context::getCurrent()->getRequest();
	}

	public function incomingReplication($id='', $xmlId='', $action='', $accessToken='')
	{
		$result = new Result();
		$instance = Manager::getInstance();

		if($instance->isActive() == false)
			return $result;

		//region debug
		if($id === '')
			$id = $this->request->getPost('data')['FIELDS']['ID'];
		if($xmlId === '')
			$xmlId = $this->request->getPost('data')['FIELDS']['XML_ID'];
		if($action === '')
			$action = $this->request->getPost('data')['FIELDS']['ACTION'];
		if($accessToken === '')
			$accessToken = $this->request->getPost('auth')['access_token'];
		//endregion

		LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_INCOMING_REQUEST', var_export(['id'=>$id, 'xmlId'=>$xmlId,' action'=>$action, 'accessToken'=>$accessToken], true));
		LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_FLAGS', var_export(['action'=>$instance->getAction()], true));

		$r = $instance->getClient()->checkAccessToken($accessToken);
		if($r->isSuccess())
		{
			LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_CHECK_ACCESS_TOKEN_SUCCESS', var_export(['access_token'=>$accessToken], true));

			$instance->setAccessToken($accessToken);

			if($action == self::MODE_DELETE)
			{
				//TODO: обработать ситуацию при которой пришел запрос на удаленеи заказа из внешней сиистемы, но заказ не был удален по причине ошибки

				LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_FILTER_BY_XML_ID', var_export(['xmlId'=>$xmlId], true));

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

				/** @var Order[] $orders */
				$orders = $orderClass::loadByFilter(['filter'=>['XML_ID'=>$xmlId]]);
				if(count($orders)>0)
				{
					LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_FILTER_BY_XML_ID_SUCCESS', var_export($orders, true));

					$controllerOrder = new \Bitrix\Sale\Controller\Order();
					LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_DELETED_BY_INTERNAL_ID', var_export($orders[0], true));

					/** @var Result $r */
					$controllerOrder->importDeleteAction($orders[0]);
					if(count($controllerOrder->getErrors())>0)
					{
						$r->addErrors($controllerOrder->getErrors());
						LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_DELETED_BY_INTERNAL_ID_ERROR');
					}
					else
						LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_DELETED_BY_INTERNAL_ID_SUCCESS');
				}
				else
				{
					$r->addError(new Error('Order not found', 'ORDER_NOT_FOUND'));
					LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_FILTER_BY_XML_ID_ERROR');
				}
			}
			elseif($action == self::MODE_SAVE)
			{
				LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_REQUEST_EXTERNAL_ENTITY_BY_ID', var_export(['id'=>$id], true));

				$r = $instance->getClient()->call(
					'sale.order.get',
					[
						'auth'=>$accessToken,
						'id'=>$id
					]
				);
				if($r->isSuccess())
				{
					LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_REQUEST_EXTERNAL_ENTITY_BY_ID_SUCCESS', var_export(['sale.order.get'=>$r->getData()['DATA']['result']], true));

					$r = $this->import($r->getData()['DATA']['result']);
					if($r->isSuccess())
					{
						$result->setData(['DATA'=>$r->getData()['DATA']]);

						$orderId = isset($r->getData()['DATA']['ORDER']['ID'])?$r->getData()['DATA']['ORDER']['ID']:0;
						$siteId = isset($r->getData()['DATA']['ORDER']['LID'])?$r->getData()['DATA']['ORDER']['LID']:'';

						self::addMarkedTimelineExternalSystem($id,
							[
								'direction'=>'incoming',
								'type'=>'success',
								'orderId'=>$orderId,
								'siteId'=>$siteId
							]
						);

						self::addActionOrderHistory(
							[
								'orderId'=>$orderId,
								'typeName'=>'ORDER_SYNCHRONIZATION_IMPORT',
								'fields'=>['EXTERNAL_ORDER_ID'=>$id]
							]
						);
					}
					else
					{
						self::addMarkedTimelineExternalSystem($id,
							[
								'direction'=>'incoming',
								'type'=>'failed',
								'errorMessage'=>$r->getErrorMessages()[0]
							]
						);
					}
				}
				else
					LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_REQUEST_EXTERNAL_ENTITY_BY_ID_ERROR');
			}
			else
			{
				$r = new Result();
				$r->addError(new Error('Action udefined'));
				LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_UNKNOWN_COMMAND', var_export(['action'=>$action], true));
			}
		}
		else
			LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_CHECK_ACCESS_TOKEN_ERROR');

		if(!$r->isSuccess())
		{
			$result->addErrors($r->getErrors());
			LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_RESULT_ERROR', var_export([
				'parameters'=>[
					'action'=>$action,
					'id'=>$id,
					'xmlId'=>$xmlId,
					'auth'=>$accessToken,
					'errors'=>$result->getErrorMessages()
				]], true));

			//return new EventResult( EventResult::ERROR, ResultError::create(current($orderController->getErrors())), 'sale');
		}
		else
		{
			LoggerDiag::addMessage('SYNCHRONIZER_INCOMING_REPLICATION_RESULT_SUCCESS', var_export([
				'id'=>$id,
				'xmlId'=>$xmlId,
				'action'=>$action,
				'result'=>$result->getData()['DATA']
			], true));
		}

		//return new EventResult( EventResult::SUCCESS, null, 'sale');
		return $result;
	}

	public function onSaleOrderSaved(Order $order)
	{
		$instance = Manager::getInstance();

		//TODO: блокировка исходящих rest-вызовов
		if($instance->getAction() == Manager::ACTION_DELETED)
			return new EventResult( EventResult::SUCCESS, null, 'sale');

		if($instance->getAction() == Manager::ACTION_IMPORT)
			return new EventResult( EventResult::SUCCESS, null, 'sale');

		self::outcomingReplication($order, self::MODE_SAVE);

		return true;
	}

	public function onSaleBeforeOrderDelete(Order $order)
	{
		//TODO: huck для блокировки исходящего события. Блокируется действием - deleted т.к. запрос исходящий
		// и удаление происходит на текущем хосте. Можно переделять на установку updated_1c=Y и проверку его сосотояния,
		// но на данный момент механизм не рабочий
		$instance = Manager::getInstance();
		$instance->setAction(Manager::ACTION_DELETED);

		self::outcomingReplication($order, self::MODE_DELETE);
		return true;
	}

	public static function outcomingReplication(Order $order, $mode)
	{
		$result = new Result();

		$instance = Manager::getInstance();

		if($instance->isActive() == false)
			return $result;

		LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_OUTCOMING_REQUEST', var_export(['id'=>$order->getId(), 'mode'=>$mode], true));
		LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_FLAGS', var_export(['action'=>$instance->getAction()], true));

		$synchronizer = new self();
		$r = $synchronizer->refreshToken();
		if($r->isSuccess())
		{
			LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REFRESH_ACCESS_TOKEN_SUCCESS', var_export(['auth'=>$instance->getAccessToken()], true));

			if($mode == self::MODE_DELETE)
			{
				$xmlId = $order->getField('XML_ID')<>'' ? $order->getField('XML_ID'):'';

				LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_EXTERNAL_ENTITY_BY_XML_ID', var_export(['xmlId'=>$xmlId], true));

				$r = $instance->getClient()->call(
					'sale.order.list',
					[
						'auth'=>$instance->getAccessToken(),
						'select'=>[],
						'filter'=>[
							'xmlId'=>$xmlId
						]
					]
				);

				if($r->isSuccess())
				{
					LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_EXTERNAL_ENTITY_BY_XML_ID_SUCCESS', var_export(['sale.order.list'=>$r->getData()['DATA']], true));

					if(count($r->getData()['DATA']['result']['orders'])>0)
					{
						$fields = $r->getData()['DATA']['result']['orders'][0];
						if($fields['id']>0)
						{
							LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_DELETED_EXTERNAL_ENTITY_BY_ID', var_export(['id'=>$fields['id']], true));
							$r = $instance->getClient()->call(
								'sale.order.importdelete',
								[
									'auth'=>$instance->getAccessToken(),
									'id'=>$fields['id']
								]
							);
							if($r->isSuccess())
							{
								LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_DELETED_EXTERNAL_ENTITY_BY_ID_SUCCESS', var_export(['sale.order.importdelete.result'=>$r->getData()['DATA']], true));

								if($r->getData()['DATA']['result']<>1)
								{
									LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_RESULT_DELETED_EXTERNAL_ENTITY_BY_ID_ERROR');
									$result->addError(new Error('Error delete - '.$fields['id'], 'ERROR_DELETED_EXTERNAL_ORDER'));
								}
								else
									LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_RESULT_DELETED_EXTERNAL_ENTITY_BY_ID_SUCCESS');
							}
							else
								LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_DELETED_EXTERNAL_ENTITY_BY_ID_ERROR');
						}
						else
							LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_PROCESS_GET_ID');
					}
					else
						LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_LIST_EXTERNAL_ENTITIES_BY_XML_ID_ERROR');
				}
				else
					LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_ERROR');
			}
			elseif($mode == self::MODE_SAVE)
			{
				$controllerOrder = new \Bitrix\Sale\Controller\Order();

				$r = $synchronizer->requesPrepareData(
					$controllerOrder->getAction($order)
				);
				if($r->isSuccess())
				{
					LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_GET_INTERNAL_FIELDS', var_export(['fields'=>$r->getData()['DATA']], true));
					$client = $instance->getClient();
					$r = $client->call(
						'sale.order.import',
						[
							'auth'=>$instance->getAccessToken(),
							'fields'=>$r->getData()['DATA']
						]
					);

					if($r->isSuccess())
					{
						// TODO: необходимо для БУС фиксировать изменения по заказу, включая отправку во внешнии сиситемы в исории заказа
						$externalOrderId = $r->getData()['DATA']['result']['order']['id'];
						if(intval($externalOrderId)>0)
						{
							self::addMarkedTimelineExternalSystem($externalOrderId,
								[
									'direction'=>'outcoming',
									'type'=>'success',
									'orderId'=>$order->getId(),
									'siteId'=>$order->getSiteId()
								]
							);
						}

						LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_GET_INTERNAL_FIELDS_SUCCESS', var_export(['sale.order.import.result'=>$r->getData()['DATA']], true));
					}
					else
						LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_GET_INTERNAL_FIELDS_ERROR');
				}
				else
					LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REQUEST_PREPARE_DATA_FIELDS_ERROR');
			}
			else
			{
				$r = new Result();
				$r->addError(new Error('Mode udefined'));
				LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_UNKNOWN_COMMAND', var_export(['mode'=>$mode], true));
			}

			if(!$r->isSuccess())
				$result->addErrors($r->getErrors());
		}
		else
		{
			LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_REFRESH_ACCESS_TOKEN_ERROR', var_export($r->getErrorMessages(), true));
			$result->addError(new Error('refresh token error'));
		}

		if($result->isSuccess())
		{
			self::addActionOrderHistory(
				[
					'order'=>$order,
					'orderId'=>$order->getId(),
					'typeName'=>'ORDER_SYNCHRONIZATION_EXPORT'
				]
			);

			EntityMarker::deleteByFilter([
				'CODE'=>self::SYNCHRONIZER_MARKER_ERROR,
				'ORDER_ID'=>$order->getId(),
				'ENTITY_ID'=>$order->getId()
			]);

			OrderTable::update($order->getId(), ['MARKED'=>'N']);

			LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_OUTCOMING_REQUEST_SUCCESS', var_export([
				'orderId'=>$order->getId(),
				'mode'=>$mode,
				'result'=>$r->getData()['DATA']
			], true));
		}
		else
		{
			self::addActionOrderHistory(
				[
					'order'=>$order,
					'orderId'=>$order->getId(),
					'typeName'=>'ORDER_SYNCHRONIZATION_EXPORT_ERROR',
					'fields'=>[
						'ERROR' => $result->getErrorMessages()
					]
				]
			);

			if($instance->isMarked())
			{
				$result->addWarning(new Error(Loc::getMessage('SYNCH_OUTCOMING_REPLICATION_OUTCOMING_ORDER_ERROR', ['#ERROR_MESSAGE#'=>$result->getErrorMessages()[0]]), self::SYNCHRONIZER_MARKER_ERROR));
				EntityMarker::addMarker($order, $order, $result);
				$r = EntityMarker::saveMarkers();

				if($r->isSuccess())
					OrderTable::update($order->getId(), ['MARKED'=>'Y']);
			}

			LoggerDiag::addMessage('SYNCHRONIZER_OUTCOMING_REPLICATION_OUTCOMING_REQUEST_ERROR', var_export($result->getErrorMessages(), true));
		}
		return $result;
	}

	public function refreshToken()
	{
		$instance = Manager::getInstance();
		/** @var Client $client */
		$client = $instance->getClient();
		$r = $client->refreshToken($instance->getRefreshToken());
		if($r->isSuccess())
		{
			$data = $r->getData()['DATA'];

			$instance->setAccessToken($data['access_token']);
			$instance->setRefreshToken($data['refresh_token']);
		}

		return $r;
	}

	public function requesPrepareData(array $fields)
	{
		$result = new Result();
		$manager = new Manager();

		// ключ tradeBindings не выгружаем т.к. при его выгрузке и пустом массиве все связки в внешней сиситеме будут удалены.
		// наиболее частый случий соответствие между внешней сиситемой и внутренней выставляться не будет.
		//if(count($fields['ORDER']['TRADE_BINDINGS'])>0)
		//{
		//	foreach($fields['ORDER']['TRADE_BINDINGS'] as $k=>$item)
		//	{
		//		$fields['ORDER']['TRADE_BINDINGS'][$k]['FIELDS'] = array_intersect_key($item['FIELDS'], $restTradeBinding->getFieldsForShow());
		//	}
		//}

		// для решения зазада - 'внешние заказы в Б24 должны иметь свой источник'
		// переписываем источник заказа из настройки синхронизции на источник внешней системы
		// метод используется только для БУС.
		if($manager->getTradePlatformsXmlId($fields['ORDER']['LID'])<>'')
		{
			$fields['ORDER']['TRADE_BINDINGS'][] = [
				'XML_ID'=>$fields['ORDER']['ID'],
				'EXTERNAL_ORDER_ID'=>$fields['ORDER']['ID'],
				'TRADING_PLATFORM_XML_ID'=>$manager->getTradePlatformsXmlId($fields['ORDER']['LID'])
			];
		}

		$externalizer = new Externalizer('import', [], new \Bitrix\Sale\Controller\Order(), $fields, Controller::SCOPE_REST);
		$fields = $externalizer->process()->getData()['data'];

		//$fields = $coverter->process($fields);

		$respons = new \Bitrix\Main\Engine\Response\Json($fields);
		$fields = \Bitrix\Main\Web\Json::decode($respons->getContent());

		if(is_array($fields) && count($fields)>0)
		{
			$result->setData(['DATA'=>$fields]);
		}
		else
		{
			$result->addError(new Error('Reques prepare data empty respons'));
		}

		return $result;
	}

	protected function import(array $fields)
	{
		$r = new Result();
		$errors=[];

		$internalizer = new Internalizer('import', ['fields'=>$fields], new \Bitrix\Sale\Controller\Order(), [], Controller::SCOPE_REST);
		$process = $internalizer->process();

		if($process->isSuccess())
		{
			$fields = $process->getData()['data']['fields'];

			LoggerDiag::addMessage('SYNCHRONIZER_IMPORT_FIELDS', var_export($fields, true));

			$orderController = new \Bitrix\Sale\Controller\Order();

			try
			{
				$result = $orderController->importAction($fields);
			}
			catch (\Bitrix\Main\SystemException $e)
			{
				$errors[] = new Error('SYNCH_OUTCOMING_REPLICATION_IMPORT_INTERNAL_ERROR');
				LoggerDiag::addMessage('SYNCHRONIZER_IMPORT_FIELDS_EXCEPTION', var_export($e->getTraceAsString(), true));
			}

			if(count($orderController->getErrors())>0)
			{
				$errors = $orderController->getErrors();
			}
		}
		else
		{
			$errors = $r->getErrors();
		}

		if(count($errors)>0)
		{
			$r->addErrors($errors);
			LoggerDiag::addMessage('SYNCHRONIZER_IMPORT_FIELDS_ERROR', var_export($errors, true));
		}
		else
		{
			$r->setData(['DATA'=>$result]);
			LoggerDiag::addMessage('SYNCHRONIZER_IMPORT_FIELDS_SUCCESS', var_export($result, true));
		}

		return $r;
	}

	protected static function addMarkedTimelineExternalSystem($externalOrderId, array $params)
	{
		$typeId = 0;
		$message = '';
		$siteName = '';

		$sites = self::getSites();
		$instance = Manager::getInstance();

		if($params['type'] == 'success')
			$typeId = 2;
		elseif ($params['type']== 'failed')
			$typeId = 5;

		if(isset($params['siteId']) && $params['siteId']<>'')
			$siteName = isset($sites[$params['siteId']])?$sites[$params['siteId']]['NAME']:'';
		if($siteName == '')
			$siteName =  $sites[SITE_ID]['NAME'];

		if($params['direction'] == 'incoming')
		{
			if($params['type'] == 'success')
			{
				$message = Loc::getMessage('SYNCH_OUTCOMING_REPLICATION_EXTERNAL_SYSTEM_MESS_EXPORT_ORDER_SUCCESS', [
					'#EXTERNAL_SYSTEM#'=>($siteName<>''?' ('.$siteName.')':''),
					'#ORDER_ID#'=>($params['orderId']>0?$params['orderId']:'')
				]);
			}
			else
			{
				$message = Loc::getMessage('SYNCH_OUTCOMING_REPLICATION_EXTERNAL_SYSTEM_MESS_EXPORT_ORDER_ERROR', [
					'#EXTERNAL_SYSTEM#'=>($siteName<>''?' ('.$siteName.')':''),
					'#ERROR_MESSAGE#'=>($params['errorMessage']<>''?$params['errorMessage']:'')
				]);
			}
		}
		if($params['direction'] == 'outcoming')
		{
			$message = Loc::getMessage('SYNCH_OUTCOMING_REPLICATION_EXTERNAL_SYSTEM_MESS_IMPORT_EXTERNAL_ORDER', [
				'#EXTERNAL_SYSTEM#'=>($siteName<>''?' ('.$siteName.')':''),
				'#ORDER_ID#'=>($params['orderId']>0?$params['orderId']:'')
			]);
		}

		$instance->getClient()->call(
			'sale.synchronizer.addTimelineAfterOrderModify',
			[
				'auth'=>$instance->getAccessToken(),
				'orderId'=>$externalOrderId,
				'params'=>[
					'type'=>$typeId,
					'message'=>$message
				]
			]
		);
	}

	/**
	 * @param array $params
	 * запись в историю осуществляется только для БУС. Для Б24 изменения по заказу пишутся в тайм лайн
	 */
	private static function addActionOrderHistory(array $params)
	{
		$params['order'] = (isset($params['order']) && ($params['order'] instanceof Order)) ? $params['order']:null;
		$params['fields'] = isset($params['fields']) ? $params['fields']:[];

		$registry = Registry::getInstance(Registry::REGISTRY_TYPE_ORDER);
		/** @var OrderHistory $orderHistory */
		$orderHistory = $registry->getOrderHistoryClassName();

		$orderHistory::addAction(
			'ORDER',
			$params['orderId'],
			$params['typeName'],
			$params['orderId'],
			$params['order'],
			$params['fields']
		);
		$orderHistory::collectEntityFields('ORDER', $params['orderId']);
	}

	protected static function getSites()
	{
		$result=[];
		$r = \CSite::GetList();
		while ($row = $r->fetch())
			$result[$row['ID']]=$row;

		return $result;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit