%PDF- %PDF- 403WebShell
403Webshell
Server IP : 37.220.80.31  /  Your IP : 18.116.24.97
Web Server : Apache/2.4.52 (Ubuntu)
System : Linux 3051455-guretool.twc1.net 5.15.0-107-generic #117-Ubuntu SMP Fri Apr 26 12:26:49 UTC 2024 x86_64
User : www-root ( 1010)
PHP Version : 7.4.33
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/www-root/data/www/dev.artlot24.ru/bitrix/modules/sale/lib/paysystem/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/www-root/data/www/dev.artlot24.ru/bitrix/modules/sale/lib/paysystem/restservice.php
<?php

namespace Bitrix\Sale\PaySystem;

use Bitrix\Main;
use Bitrix\Rest;
use Bitrix\Rest\AccessException;
use Bitrix\Rest\RestException;
use Bitrix\Sale\BusinessValue;
use Bitrix\Sale\Internals;
use Bitrix\Sale\Order;
use Bitrix\Sale\Payment;
use Bitrix\Sale\Registry;
use Bitrix\Sale\Services\PaySystem\Restrictions;
use Bitrix\Crm\Invoice;

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

/**
 * Class RestService
 * @package Bitrix\Sale\PaySystem
 */
class RestService extends \IRestService
{
	const SCOPE = 'pay_system';

	const ERROR_CHECK_FAILURE = 'ERROR_CHECK_FAILURE';
	const ERROR_HANDLER_ALREADY_EXIST = 'ERROR_HANDLER_ALREADY_EXIST';
	const ERROR_HANDLER_NOT_FOUND = 'ERROR_HANDLER_NOT_FOUND';
	const ERROR_PERSON_TYPE_NOT_FOUND = 'ERROR_PERSON_TYPE_NOT_FOUND';
	const ERROR_PAY_SYSTEM_NOT_FOUND = 'ERROR_PAY_SYSTEM_NOT_FOUND';

	private const ERROR_HANDLER_ADD = 'ERROR_HANDLER_ADD';
	private const ERROR_HANDLER_UPDATE = 'ERROR_HANDLER_UPDATE';
	private const ERROR_HANDLER_DELETE = 'ERROR_HANDLER_DELETE';

	const ERROR_PAY_SYSTEM_ADD = 'ERROR_PAY_SYSTEM_ADD';
	const ERROR_PAY_SYSTEM_UPDATE = 'ERROR_PAY_SYSTEM_UPDATE';
	const ERROR_PAY_SYSTEM_DELETE = 'ERROR_PAY_SYSTEM_DELETE';

	const ERROR_INTERNAL_INVOICE_NOT_FOUND = 'ERROR_INTERNAL_INVOICE_NOT_FOUND';
	const ERROR_INTERNAL_ORDER_NOT_FOUND = 'ERROR_INTERNAL_ORDER_NOT_FOUND';
	const ERROR_PROCESS_REQUEST_RESULT = 'ERROR_PROCESS_REQUEST_RESULT';
	const ERROR_PAY_INVOICE_NOT_SUPPORTED = 'ERROR_INVOICE_NO_SUPPORTED';

	private const ALLOWED_PAYSYSTEM_FIELDS = [
		'ID', 'PERSON_TYPE_ID', 'NAME', 'PSA_NAME', 'SORT', 'DESCRIPTION', 'ACTION_FILE', 'RESULT_FILE',
		'NEW_WINDOW', 'TARIF', 'PS_MODE', 'HAVE_PAYMENT', 'HAVE_ACTION', 'HAVE_RESULT', 'HAVE_PREPAY',
		'HAVE_PRICE', 'HAVE_RESULT_RECEIVE', 'ENCODING', 'LOGOTIP', 'ACTIVE', 'ALLOW_EDIT_PAYMENT',
		'IS_CASH', 'AUTO_CHANGE_1C', 'CAN_PRINT_CHECK', 'ENTITY_REGISTRY_TYPE', 'XML_ID'
	];

	public static function onRestAppDelete(array $fields): void
	{
		if (!Main\Loader::includeModule('rest'))
		{
			return;
		}

		if (empty($fields['APP_ID']) || empty($fields['CLEAN']) || $fields['CLEAN'] !== true)
		{
			return;
		}

		$app = Rest\AppTable::getByClientId($fields['APP_ID']);
		if (!$app)
		{
			return;
		}

		$restHandlerResult = Internals\PaySystemRestHandlersTable::getList([
			'select' => ['ID', 'CODE'],
			'filter' => [
				'=APP_ID' => $app['CLIENT_ID'],
			],
		]);
		while ($restHandler = $restHandlerResult->fetch())
		{
			$paySystemResult = Manager::getList([
				'select' => ['ID'],
				'filter' => [
					'=ACTION_FILE' => $restHandler['CODE'],
				],
			]);
			while ($paySystem = $paySystemResult->fetch())
			{
				Manager::delete($paySystem['ID']);
			}

			Internals\PaySystemRestHandlersTable::delete($restHandler['ID']);
		}
	}

	/**
	 * @return array
	 */
	public static function onRestServiceBuildDescription()
	{
		return [
			static::SCOPE => [
				'sale.paysystem.handler.add' => [__CLASS__, 'addHandler'],
				'sale.paysystem.handler.update' => [__CLASS__, 'updateHandler'],
				'sale.paysystem.handler.delete' => [__CLASS__, 'deleteHandler'],
				'sale.paysystem.handler.list' => [__CLASS__, 'getHandlerList'],

				'sale.paysystem.add' => [__CLASS__, 'addPaySystem'],
				'sale.paysystem.update' => [__CLASS__, 'updatePaySystem'],
				'sale.paysystem.delete' => [__CLASS__, 'deletePaySystem'],
				'sale.paysystem.list' => [__CLASS__, 'getPaySystemList'],

				'sale.paysystem.settings.get' => [__CLASS__, 'getSettings'],
				'sale.paysystem.settings.update' => [__CLASS__, 'updateSettings'],

				'sale.paysystem.settings.invoice.get' => [__CLASS__, 'getSettingsByInvoice'],
				'sale.paysystem.settings.payment.get' => [__CLASS__, 'getSettingsByPayment'],

				'sale.paysystem.pay.invoice' => [__CLASS__, 'payInvoice'],
				'sale.paysystem.pay.payment' => [__CLASS__, 'payPayment'],
			]
		];
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return array|int
	 * @throws RestException
	 */
	public static function addPaySystem(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$params = self::preparePaySystemParams($params, $server);

		if (!isset($params['ENTITY_REGISTRY_TYPE']))
		{
			if (IsModuleInstalled('crm'))
			{
				$params['ENTITY_REGISTRY_TYPE'] = REGISTRY_TYPE_CRM_INVOICE;
			}
			else
			{
				$params['ENTITY_REGISTRY_TYPE'] = Registry::REGISTRY_TYPE_ORDER;
			}
		}

		static::checkParamsBeforePaySystemAdd($params);

		$fields = [
			'NAME' => $params['NAME'],
			'PSA_NAME' => $params['NAME'],
			'NEW_WINDOW' => $params['NEW_WINDOW'] ?: 'N',
			'ACTIVE' => $params['ACTIVE'] ?: 'N',
			'PERSON_TYPE_ID' => $params['PERSON_TYPE_ID'],
			'ACTION_FILE' => $params['BX_REST_HANDLER'],
			'HAVE_PREPAY' => 'N',
			'HAVE_RESULT' => 'N',
			'HAVE_ACTION' => 'N',
			'HAVE_PAYMENT' => 'N',
			'HAVE_RESULT_RECEIVE' => 'Y',
			'ENTITY_REGISTRY_TYPE' => $params['ENTITY_REGISTRY_TYPE'],
		];

		if (isset($params['LOGOTIP']))
		{
			$fields['LOGOTIP'] = self::saveFile($params['LOGOTIP']);
		}

		$result = Manager::add($fields);
		if ($result->isSuccess())
		{
			$id = $result->getId();
			Manager::update($id, array('PAY_SYSTEM_ID' => $id));

			foreach ($params['SETTINGS'] as $key => $value)
			{
				BusinessValue::setMapping(
					$key,
					Service::PAY_SYSTEM_PREFIX.$id,
					$params['PERSON_TYPE_ID'],
					[
						'PROVIDER_KEY' => $value['TYPE'],
						'PROVIDER_VALUE' => $value['VALUE']
					]
				);
			}

			if ($fields['PERSON_TYPE_ID'] > 0)
			{
				static::savePersonTypeId($id, $params['PERSON_TYPE_ID']);
			}

			static::logAnalytics(
				'addPaySystem' . $params['ENTITY_REGISTRY_TYPE'],
				$params['BX_REST_HANDLER'],
				$params['PERSON_TYPE_ID'],
				$server
			);

			return $id;
		}

		$error = implode("\n", $result->getErrorMessages());
		throw new RestException($error, self::ERROR_PAY_SYSTEM_ADD);
	}

	/**
	 * @param $params
	 * @throws RestException
	 * @throws AccessException
	 */
	protected static function checkParamsBeforePaySystemAdd($params)
	{
		if (empty($params['BX_REST_HANDLER']))
		{
			throw new RestException('Parameter BX_REST_HANDLER is not defined', self::ERROR_CHECK_FAILURE);
		}

		$handlerData = self::getHandlerData($params['BX_REST_HANDLER']);
		if (!$handlerData)
		{
			throw new RestException('Handler not found', self::ERROR_HANDLER_NOT_FOUND);
		}

		if ($params['APP_ID'] && !empty($handlerData['APP_ID']) && $handlerData['APP_ID'] !== $params['APP_ID'])
		{
			throw new AccessException();
		}

		$dbRes = Internals\PersonTypeTable::getList([
			'filter' => [
				'=ID' => $params['PERSON_TYPE_ID'],
				'=ENTITY_REGISTRY_TYPE' => $params['ENTITY_REGISTRY_TYPE'],
			]
		]);
		if (!$dbRes->fetch())
		{
			throw new RestException('Incorrect person type id!', self::ERROR_PERSON_TYPE_NOT_FOUND);
		}
	}

	/**
	 * @param $serviceId
	 * @param $personTypeId
	 */
	private static function savePersonTypeId($serviceId, $personTypeId)
	{
		$params = [
			'filter' => [
				"SERVICE_ID" => $serviceId,
				"SERVICE_TYPE" => Restrictions\Manager::SERVICE_TYPE_PAYMENT,
				"=CLASS_NAME" => '\\'.Restrictions\PersonType::class
			]
		];

		$dbRes = Internals\ServiceRestrictionTable::getList($params);
		if ($data = $dbRes->fetch())
		{
			$restrictionId = $data['ID'];
		}
		else
		{
			$restrictionId = 0;
		}

		$fields = array(
			"SERVICE_ID" => $serviceId,
			"SERVICE_TYPE" => Restrictions\Manager::SERVICE_TYPE_PAYMENT,
			"SORT" => 100,
			"PARAMS" => array('PERSON_TYPE_ID' => array($personTypeId))
		);

		Restrictions\PersonType::save($fields, $restrictionId);
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return bool
	 */
	public static function updatePaySystem(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$params = self::preparePaySystemParams($params, $server);

		static::checkParamsBeforePaySystemUpdate($params);

		$fields = array();
		if (isset($params['FIELDS']['NAME']))
		{
			$fields['NAME'] = $params['FIELDS']['NAME'];
		}

		if (isset($params['FIELDS']['NEW_WINDOW']))
		{
			$fields['NEW_WINDOW'] = $params['FIELDS']['NEW_WINDOW'];
		}

		if (isset($params['FIELDS']['ACTIVE']))
		{
			$fields['ACTIVE'] = $params['FIELDS']['ACTIVE'];
		}

		if (isset($params['FIELDS']['PERSON_TYPE_ID']))
		{
			$fields['PERSON_TYPE_ID'] = $params['FIELDS']['PERSON_TYPE_ID'];
		}

		if (isset($params['FIELDS']['BX_REST_HANDLER']))
		{
			$fields['ACTION_FILE'] = $params['FIELDS']['BX_REST_HANDLER'];
		}

		if (isset($params['FIELDS']['LOGOTIP']))
		{
			$fields['LOGOTIP'] = self::saveFile($params['FIELDS']['LOGOTIP']);
		}

		$result = Manager::update($params['ID'], $fields);

		if ($fields['PERSON_TYPE_ID'] > 0)
		{
			static::savePersonTypeId($params['ID'], $fields['PERSON_TYPE_ID']);
		}

		return $result->isSuccess();
	}

	/**
	 * @param $params
	 * @throws RestException
	 * @throws AccessException
	 */
	protected static function checkParamsBeforePaySystemUpdate($params)
	{
		$handlerList = Manager::getHandlerList();

		$handler = $params['FIELDS']['BX_REST_HANDLER'];
		if (!isset($handlerList['USER'][$handler]) && !isset($handlerList['SYSTEM'][$handler]))
		{
			throw new RestException('Handler not found', self::ERROR_HANDLER_NOT_FOUND);
		}

		$dbRes = Manager::getList([
			'filter' => [
				'ID' => $params['ID']
			]
		]);

		$data = $dbRes->fetch();
		if (!$data)
		{
			throw new RestException('Pay system not found', self::ERROR_PAY_SYSTEM_NOT_FOUND);
		}

		if (!self::hasAccessToPaySystem($data, $params['APP_ID']))
		{
			throw new AccessException();
		}

		$dbRes = Internals\PersonTypeTable::getList([
			'filter' => [
				'=ID' => $params['FIELDS']['PERSON_TYPE_ID'],
				'=ENTITY_REGISTRY_TYPE' => $data['ENTITY_REGISTRY_TYPE'],
			]
		]);
		if (!$dbRes->fetch())
		{
			throw new RestException('Incorrect person type id!', self::ERROR_PERSON_TYPE_NOT_FOUND);
		}
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return bool
	 * @throws RestException
	 */
	public static function updateSettings(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$params = self::preparePaySystemParams($params, $server);

		static::checkParamsBeforeSettingsUpdate($params);

		foreach ($params['SETTINGS'] as $field => $value)
		{
			$result = BusinessValue::setMapping(
				$field,
				Service::PAY_SYSTEM_PREFIX.$params['ID'],
				$params['PERSON_TYPE_ID'],
				[
					'PROVIDER_KEY' => $value['TYPE'],
					'PROVIDER_VALUE' => $value['VALUE']
				]
			);

			if (!$result->isSuccess())
			{
				return false;
			}
		}

		return true;
	}

	/**
	 * @param $params
	 * @throws RestException
	 */
	protected static function checkParamsBeforeSettingsUpdate($params)
	{
		if (!isset($params['ID']))
		{
			throw new RestException('Parameter ID is not defined', self::ERROR_CHECK_FAILURE);
		}

		$item = Manager::getById($params['ID']);
		if (!$item)
		{
			throw new RestException('Pay system not found', static::ERROR_CHECK_FAILURE);
		}

		if (!isset($params['SETTINGS']) || empty($params['SETTINGS']))
		{
			throw new RestException('Parameter SETTINGS is not defined or empty', self::ERROR_HANDLER_NOT_FOUND);
		}

		if (!self::hasAccessToPaySystem($item, $params['APP_ID']))
		{
			throw new AccessException();
		}
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return array
	 */
	public static function getSettings(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$params = self::preparePaySystemParams($params, $server);

		static::checkParamsBeforeSettingsGet($params);

		$result = [];

		$consumers = BusinessValue::getConsumers();
		$codes = $consumers[Service::PAY_SYSTEM_PREFIX.$params['ID']]['CODES'];

		foreach ($codes as $field => $value)
		{
			$mapping = BusinessValue::getMapping(
				$field,
				Service::PAY_SYSTEM_PREFIX.$params['ID'],
				$params['PERSON_TYPE_ID']
			);

			$result[$field] = [
				'TYPE' => $mapping['PROVIDER_KEY'],
				'VALUE' => $mapping['PROVIDER_VALUE']
			];
		}

		return $result;
	}

	/**
	 * @param $params
	 * @throws RestException
	 * @throws AccessException
	 */
	protected static function checkParamsBeforeSettingsGet($params)
	{
		if (!isset($params['PERSON_TYPE_ID']))
		{
			throw new RestException('Parameter PERSON_TYPE_ID is not defined', self::ERROR_CHECK_FAILURE);
		}

		if (!isset($params['ID']))
		{
			throw new RestException('Parameter ID is not defined', self::ERROR_CHECK_FAILURE);
		}

		$item = Manager::getById($params['ID']);
		if (!$item)
		{
			throw new RestException('Pay system not found', static::ERROR_CHECK_FAILURE);
		}

		if (!self::hasAccessToPaySystem($item, $params['APP_ID']))
		{
			throw new AccessException();
		}
	}

	/**
	 * @param array $params
	 * @return bool
	 */
	public static function deletePaySystem(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$params = self::preparePaySystemParams($params, $server);

		static::checkParamsBeforePaySystemDelete($params);

		$result = Manager::delete($params['ID']);

		return $result->isSuccess();
	}

	/**
	 * @param $params
	 * @throws AccessException
	 * @throws RestException
	 */
	protected static function checkParamsBeforePaySystemDelete($params)
	{
		$data = Manager::getById($params['ID']);
		if (!$data)
		{
			throw new RestException('Pay system not found', self::ERROR_PAY_SYSTEM_NOT_FOUND);
		}

		if (!self::hasAccessToPaySystem($data, $params['APP_ID']))
		{
			throw new AccessException();
		}
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return array|int
	 * @throws RestException
	 */
	public static function addHandler(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$params = self::prepareHandlerParams($params, $server);

		self::checkParamsOnAddHandler($params);

		$data = [
			'NAME' => $params['NAME'],
			'CODE' => $params['CODE'],
			'SORT' => $params['SORT'] ?: 100,
			'SETTINGS' => $params['SETTINGS'],
			'APP_ID' => $params['APP_ID'],
		];

		$result = Internals\PaySystemRestHandlersTable::add($data);
		if ($result->isSuccess())
		{
			return $result->getId();
		}

		$error = implode("\n", $result->getErrorMessages());
		throw new RestException($error, self::ERROR_HANDLER_ADD);
	}

	/**
	 * @param array $params
	 * @throws RestException
	 */
	private static function checkParamsOnAddHandler(array $params)
	{
		if (!isset($params['NAME']))
		{
			throw new RestException('Parameter NAME is not defined', self::ERROR_CHECK_FAILURE);
		}

		if (!isset($params['CODE']))
		{
			throw new RestException('Parameter CODE is not defined', self::ERROR_CHECK_FAILURE);
		}

		if (!isset($params['SETTINGS']))
		{
			throw new RestException('Parameter SETTINGS is not defined', self::ERROR_CHECK_FAILURE);
		}

		if (!isset($params['SETTINGS']['CODES']))
		{
			throw new RestException('Parameter SETTINGS[CODES] is not defined', self::ERROR_CHECK_FAILURE);
		}

		if (
			empty($params['SETTINGS']['FORM_DATA'])
			&& empty($params['SETTINGS']['CHECKOUT_DATA'])
			&& empty($params['SETTINGS']['IFRAME_DATA'])
		)
		{
			throw new RestException(
				'Parameter SETTINGS[FORM_DATA] or SETTINGS[CHECKOUT_DATA] or SETTINGS[IFRAME_DATA] is not defined',
				self::ERROR_CHECK_FAILURE
			);
		}

		if (
			!empty($params['SETTINGS']['FORM_DATA'])
			&& empty($params['SETTINGS']['FORM_DATA']['ACTION_URI'])
		)
		{
			throw new RestException('Parameter SETTINGS[FORM_DATA][ACTION_URI] is not defined', self::ERROR_CHECK_FAILURE);
		}

		if (
			!empty($params['SETTINGS']['CHECKOUT_DATA'])
			&& empty($params['SETTINGS']['CHECKOUT_DATA']['ACTION_URI'])
		)
		{
			throw new RestException('Parameter SETTINGS[IFRAME_DATA][ACTION_URI] is not defined', self::ERROR_CHECK_FAILURE);
		}

		if (
			!empty($params['SETTINGS']['IFRAME_DATA'])
			&& empty($params['SETTINGS']['IFRAME_DATA']['ACTION_URI'])
		)
		{
			throw new RestException('Parameter SETTINGS[IFRAME_DATA][ACTION_URI] is not defined', self::ERROR_CHECK_FAILURE);
		}

		$dbRes = Internals\PaySystemRestHandlersTable::getList([
			'filter' => [
				'=CODE' => $params['CODE']
			]
		]);
		if ($dbRes->fetch())
		{
			throw new RestException('Handler already exists!', self::ERROR_HANDLER_ALREADY_EXIST);
		}
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return bool
	 * @throws RestException
	 */
	public static function updateHandler(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$params = self::prepareHandlerParams($params, $server);

		self::checkParamsOnUpdateHandler($params);

		$result = Internals\PaySystemRestHandlersTable::update($params['ID'], $params['FIELDS']);
		if ($result->isSuccess())
		{
			return true;
		}

		$error = implode("\n", $result->getErrorMessages());
		throw new RestException($error, self::ERROR_HANDLER_UPDATE);
	}

	/**
	 * @param array $params
	 * @throws RestException
	 * @throws AccessException
	 */
	private static function checkParamsOnUpdateHandler(array $params)
	{
		if (!isset($params['FIELDS']))
		{
			throw new RestException('Parameter FIELDS is not defined', self::ERROR_CHECK_FAILURE);
		}

		$paySystemRestHandlers = Internals\PaySystemRestHandlersTable::getList(array(
			'filter' => array(
				'ID' => $params['ID']
			)
		))->fetch();
		if (!$paySystemRestHandlers)
		{
			throw new RestException('Handler not found', self::ERROR_HANDLER_NOT_FOUND);
		}

		if ($params['APP_ID'] && !empty($paySystemRestHandlers['APP_ID']) && $paySystemRestHandlers['APP_ID'] !== $params['APP_ID'])
		{
			throw new AccessException();
		}
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return bool
	 * @throws RestException
	 */
	public static function deleteHandler(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$params = self::prepareHandlerParams($params, $server);

		self::checkParamsOnDeleteHandler($params);

		$result = Internals\PaySystemRestHandlersTable::delete($params['ID']);
		if ($result->isSuccess())
		{
			return true;
		}

		$error = implode("\n", $result->getErrorMessages());
		throw new RestException($error, self::ERROR_HANDLER_DELETE);
	}

	/**
	 * @param $params
	 * @throws RestException
	 */
	private static function checkParamsOnDeleteHandler($params): void
	{
		$dbRes = Internals\PaySystemRestHandlersTable::getList(array(
			'filter' => array(
				'ID' => $params['ID']
			)
		));
		$data = $dbRes->fetch();
		if (!$data)
		{
			throw new RestException('Handler not found', self::ERROR_HANDLER_NOT_FOUND);
		}

		if ($params['APP_ID'] && !empty($data['APP_ID']) && $data['APP_ID'] !== $params['APP_ID'])
		{
			throw new AccessException();
		}

		$dbRes = Manager::getList(array('filter' => array('ACTION_FILE' => $data['CODE'])));
		if ($dbRes->fetch())
		{
			throw new RestException('Pay system with handler '.ToUpper($data['CODE']).' exists!', self::ERROR_PAY_SYSTEM_DELETE);
		}
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return array
	 */
	public static function getHandlerList(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();

		$result = array();
		$dbRes = Internals\PaySystemRestHandlersTable::getList([
			'select' => ['ID', 'NAME', 'CODE', 'SORT', 'SETTINGS'],
		]);
		while ($item = $dbRes->fetch())
		{
			$result[] = $item;
		}

		return $result;
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return array
	 */
	public static function getPaySystemList(array $params, $n, \CRestServer $server)
	{
		static::checkPaySystemPermission();
		$params = self::prepareIncomingParams($params);
		self::checkParamsBeforePaySystemListGet($params);

		$select =
			isset($params['SELECT']) && is_array($params['SELECT'])
				? array_flip(self::prepareIncomingParams(array_flip($params['SELECT'])))
				: self::ALLOWED_PAYSYSTEM_FIELDS
		;

		$filter = [];
		$filterFromParams = isset($params['FILTER']) && is_array($params['FILTER']) ? $params['FILTER'] : [];
		if ($filterFromParams)
		{
			$incomingFieldsMap = self::getIncomingFieldsMap();
			foreach ($filterFromParams as $rawName => $value)
			{
				$filterField = \CSqlUtil::GetFilterOperation($rawName);
				$fieldName = $incomingFieldsMap[$filterField['FIELD']] ?? $filterField['FIELD'];
				$filter[$filterField['OPERATION'] . $fieldName] = $value;
			}
		}

		$order =
			isset($params['ORDER']) && is_array($params['ORDER'])
				? self::prepareIncomingParams($params['ORDER'])
				: []
		;

		$result = array();
		$dbRes = Manager::getList([
			'select' => $select,
			'filter' => $filter,
			'order' => $order,
		]);
		while ($item = $dbRes->fetch())
		{
			$result[] = self::prepareOutcomingFields($item);
		}

		return $result;
	}

	/**
	 * @param array $params
	 * @throws RestException
	 */
	private static function checkParamsBeforePaySystemListGet(array $params)
	{
		$select = isset($params['SELECT']) && is_array($params['SELECT']) ? $params['SELECT'] : [];
		if ($select)
		{
			$select = array_flip(self::prepareIncomingParams(array_flip($select)));
			$diffSelect = array_diff($select, self::ALLOWED_PAYSYSTEM_FIELDS);

			if ($diffSelect)
			{
				throw new RestException(implode(', ', $diffSelect) . ' not allowed for select');
			}
		}

		$filter = isset($params['FILTER']) && is_array($params['FILTER']) ? $params['FILTER'] : [];
		if ($filter)
		{
			$filterFields = [];
			foreach ($filter as $rawName => $value)
			{
				$filterField = \CSqlUtil::GetFilterOperation($rawName);
				if (isset($filterField['FIELD']))
				{
					$filterFields[] = $filterField['FIELD'];
				}
			}

			$filterFields = array_flip(self::prepareIncomingParams(array_flip($filterFields)));
			$diffFilter = array_diff($filterFields, self::ALLOWED_PAYSYSTEM_FIELDS);
			if ($diffFilter)
			{
				throw new RestException(implode(', ', $diffFilter) . ' not allowed for filter');
			}
		}

		$order =
			isset($params['ORDER']) && is_array($params['ORDER'])
				? self::prepareIncomingParams($params['ORDER'])
				: []
		;
		if ($order)
		{
			$diffOrder = array_diff(array_keys($order), self::ALLOWED_PAYSYSTEM_FIELDS);
			if ($diffOrder)
			{
				throw new RestException(implode(', ', $diffOrder) . ' not allowed for order');
			}
		}
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return array
	 * @throws RestException
	 */
	public static function getSettingsByInvoice(array $params, $n, \CRestServer $server)
	{
		static::checkOrderPermission();

		$params = self::preparePaySystemParams($params, $server);

		self::checkParamsBeforeSettingsByInvoiceGet($params);

		if (isset($params['PAY_SYSTEM_ID']))
		{
			$service = Manager::getObjectById($params['PAY_SYSTEM_ID']);
		}
		else
		{
			$dbRes = Manager::getList(array('filter' => array('=ACTION_FILE' => $params['BX_REST_HANDLER'])));
			$item = $dbRes->fetch();
			if (!$item)
			{
				throw new RestException('Pay system with handler '.$params['BX_REST_HANDLER'].' not found', self::ERROR_PAY_SYSTEM_NOT_FOUND);
			}

			$service = new Service($item);
		}

		$invoice = Invoice\Invoice::load($params['INVOICE_ID']);
		if ($invoice)
		{
			$paymentCollection = $invoice->getPaymentCollection();
			if ($paymentCollection)
			{
				/** @var Payment $payment */
				foreach ($paymentCollection as $payment)
				{
					if (!$payment->isInner())
					{
						return $service->getParamsBusValue($payment);
					}
				}
			}
		}

		throw new RestException('Invoice #'.$params['INVOICE_ID'].' not found', self::ERROR_INTERNAL_INVOICE_NOT_FOUND);
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return array
	 * @throws RestException
	 */
	public static function getSettingsByPayment(array $params, $n, \CRestServer $server)
	{
		static::checkOrderPermission();

		$params = self::preparePaySystemParams($params, $server);

		self::checkParamsBeforeSettingsByPaymentGet($params);

		list($orderId, $paymentId) = Manager::getIdsByPayment($params['PAYMENT_ID']);

		$registry = Registry::getInstance(Registry::REGISTRY_TYPE_ORDER);

		/** @var Order $orderClassName */
		$orderClassName = $registry->getOrderClassName();
		$order = $orderClassName::load($orderId);
		if ($order)
		{
			$paymentCollection = $order->getPaymentCollection();

			/** @var Payment $payment */
			$payment = $paymentCollection->getItemById($paymentId);

			$service = Manager::getObjectById($params['PAY_SYSTEM_ID']);

			return $service->getParamsBusValue($payment);
		}

		throw new RestException('Order #'.$orderId.' not found', self::ERROR_INTERNAL_ORDER_NOT_FOUND);
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return bool
	 * @throws RestException
	 */
	public static function payInvoice(array $params, $n, \CRestServer $server)
	{
		if (!Main\Loader::includeModule('crm'))
		{
			throw new RestException('Pay invoice is not supported!', self::ERROR_PAY_INVOICE_NOT_SUPPORTED);
		}

		static::checkOrderPermission();

		$params = self::prepareIncomingParams($params);

		self::checkParamsForInvoice($params);

		$dbRes = Invoice\Payment::getList(array(
			'select' => array('ID'),
			'filter' => array(
				'ORDER_ID' => $params['INVOICE_ID'],
				'!PAY_SYSTEM_ID' => Manager::getInnerPaySystemId(),
			)
		));

		$payment = $dbRes->fetch();
		if (!$payment)
		{
			throw new RestException('Invoice #'.$params['INVOICE_ID'].' not found', self::ERROR_INTERNAL_INVOICE_NOT_FOUND);
		}

		$params['PAYMENT_ID'] = $payment['ID'];

		$filter = [
			'=ENTITY_REGISTRY_TYPE' => REGISTRY_TYPE_CRM_INVOICE
		];

		if (isset($params['PAY_SYSTEM_ID']))
		{
			$filter['=ID'] = $params['PAY_SYSTEM_ID'];
		}
		else
		{
			$filter['=ACTION_FILE'] = $params['BX_REST_HANDLER'];
		}

		$dbRes = Manager::getList([
			'select' => ['ID'],
			'filter' => $filter
		]);
		$item = $dbRes->fetch();
		if (!$item)
		{
			throw new RestException('Pay system not found', static::ERROR_PROCESS_REQUEST_RESULT);
		}

		$params['PAY_SYSTEM_ID'] = $item['ID'];

		return self::payPaymentInternal($params, $server);
	}

	/**
	 * @param array $params
	 * @param $n
	 * @param \CRestServer $server
	 * @return bool
	 */
	public static function payPayment(array $params, $n, \CRestServer $server)
	{
		static::checkOrderPermission();

		$params = self::prepareIncomingParams($params);

		self::checkParamsForPayment($params);

		return self::payPaymentInternal($params, $server);
	}

	/**
	 * @param array $params
	 * @param \CRestServer $restServer
	 * @return bool
	 * @throws RestException
	 */
	private static function payPaymentInternal(array $params, \CRestServer $restServer)
	{
		$context = Main\Context::getCurrent();
		$server = $context->getServer();

		$request = new Main\HttpRequest($server, array(), $params, array(), array());

		$service = Manager::getObjectById($params['PAY_SYSTEM_ID']);

		$result = $service->processRequest($request);
		if (!$result->isSuccess())
		{
			$error = join("\n", $result->getErrorMessages());
			throw new RestException($error, static::ERROR_PROCESS_REQUEST_RESULT);
		}

		static::logAnalytics(
			'payPayment' . $service->getField('ENTITY_REGISTRY_TYPE'),
			$service->getField('ACTION_FILE'),
			$service->getField('PERSON_TYPE_ID'),
			$restServer
		);

		return true;
	}

	/**
	 * @param array $data
	 * @param int $case
	 * @return array
	 */
	private static function arrayChangeKeyCaseRecursive(array $data, $case = CASE_UPPER)
	{
		return array_map(static function ($item) use ($case) {
			if (is_array($item))
			{
				$item = self::arrayChangeKeyCaseRecursive($item, $case);
			}
			return $item;
		}, array_change_key_case($data, $case));
	}

	/**
	 * @param array $data
	 * @return array
	 */
	private static function prepareIncomingParams(array $data): array
	{
		return self::replaceIncomingKeys(self::arrayChangeKeyCaseRecursive($data));
	}

	/**
	 * @param array $data
	 * @param \CRestServer $server
	 * @return array
	 */
	private static function prepareHandlerParams(array $data, \CRestServer $server): array
	{
		$data = self::prepareIncomingParams($data);
		$data['APP_ID'] = $server->getClientId();

		return $data;
	}

	private static function preparePaySystemParams(array $data, \CRestServer $server): array
	{
		$data = self::prepareIncomingParams($data);
		$data['APP_ID'] = $server->getClientId();

		return $data;
	}

	/**
	 * @param array $params
	 * @throws RestException
	 */
	private static function checkParamsForInvoice(array $params)
	{
		if (!isset($params['BX_REST_HANDLER']) && !isset($params['PAY_SYSTEM_ID']))
		{
			throw new RestException('Empty field BX_REST_HANDLER and PAY_SYSTEM_ID', self::ERROR_CHECK_FAILURE);
		}

		if (isset($params['PAY_SYSTEM_ID']))
		{
			$data = Manager::getById($params['PAY_SYSTEM_ID']);
			if (!$data)
			{
				throw new RestException('Pay system with ID='.$params['PAY_SYSTEM_ID'].' not found', static::ERROR_CHECK_FAILURE);
			}
		}

		if (isset($params['BX_REST_HANDLER']))
		{
			$dbRes = Internals\PaySystemRestHandlersTable::getList(array(
				'filter' => array(
					'=CODE' => $params['BX_REST_HANDLER']
				)
			));
			if (!$dbRes->fetch())
			{
				throw new RestException('Incorrect rest handler code', static::ERROR_CHECK_FAILURE);
			}
		}

		if (empty($params['INVOICE_ID']))
		{
			throw new RestException('Empty field INVOICE_ID!', self::ERROR_CHECK_FAILURE);
		}
	}

	/**
	 * @param array $params
	 * @throws RestException
	 * @throws AccessException
	 */
	private static function checkParamsBeforeSettingsByInvoiceGet(array $params)
	{
		if (!isset($params['BX_REST_HANDLER']) && !isset($params['PAY_SYSTEM_ID']))
		{
			throw new RestException('Empty field BX_REST_HANDLER and PAY_SYSTEM_ID', self::ERROR_CHECK_FAILURE);
		}

		if (empty($params['INVOICE_ID']))
		{
			throw new RestException('Empty field INVOICE_ID', self::ERROR_CHECK_FAILURE);
		}

		if (isset($params['PAY_SYSTEM_ID']))
		{
			$data = Manager::getById($params['PAY_SYSTEM_ID']);
			if (!$data)
			{
				throw new RestException('Pay system with ID='.$params['PAY_SYSTEM_ID'].' not found', static::ERROR_CHECK_FAILURE);
			}

			if (!self::hasAccessToPaySystem($data, $params['APP_ID']))
			{
				throw new AccessException();
			}
		}

		if (isset($params['BX_REST_HANDLER']))
		{
			$dbRes = Internals\PaySystemRestHandlersTable::getList(array(
				'filter' => array(
					'=CODE' => $params['BX_REST_HANDLER']
				)
			));

			$handlerData = $dbRes->fetch();
			if (!$handlerData)
			{
				throw new RestException('Incorrect rest handler code', static::ERROR_CHECK_FAILURE);
			}

			if ($params['APP_ID'] && !empty($handlerData['APP_ID']) && $handlerData['APP_ID'] !== $params['APP_ID'])
			{
				throw new AccessException();
			}
		}
	}

	/**
	 * @param array $params
	 * @throws Main\ArgumentException
	 * @throws RestException
	 */
	private static function checkParamsForPayment(array $params)
	{
		if (empty($params['PAY_SYSTEM_ID']))
		{
			throw new RestException('Empty field PAY_SYSTEM_ID!', self::ERROR_CHECK_FAILURE);
		}

		$item = Manager::getById($params['PAY_SYSTEM_ID']);
		if (!$item)
		{
			throw new RestException('Pay system not found', static::ERROR_CHECK_FAILURE);
		}

		if (empty($params['PAYMENT_ID']))
		{
			throw new RestException('Empty field PAYMENT_ID', self::ERROR_CHECK_FAILURE);
		}

		$registry = Registry::getInstance(Registry::REGISTRY_TYPE_ORDER);

		/** @var Payment $paymentClassName */
		$paymentClassName = $registry->getPaymentClassName();
		$dbRes = $paymentClassName::getList([
			'select' => ['ID', 'PAY_SYSTEM_ID'],
			'filter' => [
				'=ID' => $params['PAYMENT_ID'],
				'=PAY_SYSTEM_ID' => $params['PAY_SYSTEM_ID']
			]
		]);

		if (!$dbRes->fetch())
		{
			throw new RestException(
				'Payment with ID='
				. $params['PAYMENT_ID']
				. ' and PAY_SYSTEM_ID='.$params['PAY_SYSTEM_ID']
				. ' not found', self::ERROR_CHECK_FAILURE
			);
		}
	}

	/**
	 * @param array $params
	 * @throws Main\ArgumentException
	 * @throws RestException
	 */
	private static function checkParamsBeforeSettingsByPaymentGet(array $params)
	{
		if (empty($params['PAY_SYSTEM_ID']))
		{
			throw new RestException('Empty field PAY_SYSTEM_ID!', self::ERROR_CHECK_FAILURE);
		}

		if (empty($params['PAYMENT_ID']))
		{
			throw new RestException('Empty field PAYMENT_ID', self::ERROR_CHECK_FAILURE);
		}

		$item = Manager::getById($params['PAY_SYSTEM_ID']);
		if (!$item)
		{
			throw new RestException('Pay system not found', static::ERROR_CHECK_FAILURE);
		}

		if (!self::hasAccessToPaySystem($item, $params['APP_ID']))
		{
			throw new AccessException();
		}

		$registry = Registry::getInstance(Registry::REGISTRY_TYPE_ORDER);

		/** @var Payment $paymentClassName */
		$paymentClassName = $registry->getPaymentClassName();
		$dbRes = $paymentClassName::getList([
			'select' => ['ID', 'PAY_SYSTEM_ID'],
			'filter' => [
				'=ID' => $params['PAYMENT_ID'],
				'=PAY_SYSTEM_ID' => $params['PAY_SYSTEM_ID']
			]
		]);

		if (!$dbRes->fetch())
		{
			throw new RestException(
				'Payment with ID='
				. $params['PAYMENT_ID']
				. ' and PAY_SYSTEM_ID='.$params['PAY_SYSTEM_ID']
				. ' not found', self::ERROR_CHECK_FAILURE
			);
		}
	}

	/**
	 * @throws AccessException
	 * @throws Main\LoaderException
	 */
	protected static function checkOrderPermission()
	{
		global $APPLICATION;

		if (IsModuleInstalled('intranet') && Main\Loader::includeModule('crm'))
		{
			$CCrmInvoice = new \CCrmInvoice();
			if ($CCrmInvoice->cPerms->HavePerm('INVOICE', BX_CRM_PERM_NONE, 'WRITE')
				&& $CCrmInvoice->cPerms->HavePerm('INVOICE', BX_CRM_PERM_NONE, 'ADD')
			)
			{
				throw new AccessException();
			}
		}
		else
		{
			$saleModulePermissions = $APPLICATION->GetGroupRight("sale");

			if($saleModulePermissions == "D")
			{
				throw new AccessException();
			}
		}
	}

	/**
	 * @throws AccessException
	 * @throws Main\LoaderException
	 */
	protected static function checkPaySystemPermission()
	{
		\Bitrix\Sale\Helpers\Rest\AccessChecker::checkAccessPermission();
	}

	/**
	 * @param $fileContent
	 * @return false|int|string|null
	 */
	private static function saveFile($fileContent)
	{
		$file = \CRestUtil::saveFile($fileContent);
		if ($file)
		{
			$file['MODULE_ID'] = 'sale';
			return \CFile::SaveFile($file, 'sale');
		}

		return null;
	}

	/**
	 * @return string[]
	 */
	private static function getIncomingFieldsMap(): array
	{
		return [
			'LOGOTYPE' => 'LOGOTIP',
			'TARIFF' => 'TARIF',
		];
	}

	/**
	 * @return string[]
	 */
	private static function getOutcomingFieldsMap(): array
	{
		return [
			'LOGOTIP' => 'LOGOTYPE',
			'TARIF' => 'TARIFF',
		];
	}

	/**
	 * @param array $data
	 * @return array
	 */
	private static function prepareOutcomingFields(array $data): array
	{
		return self::replaceOutcomingKeys($data);
	}

	/**
	 * @param array $data
	 * @return array
	 */
	private static function replaceIncomingKeys(array $data): array
	{
		return self::replaceKeys($data, self::getIncomingFieldsMap());
	}

	/**
	 * @param array $data
	 * @return array
	 */
	private static function replaceOutcomingKeys(array $data): array
	{
		return self::replaceKeys($data, self::getOutcomingFieldsMap());
	}

	/**
	 * @param array $data
	 * @param array $map
	 * @return array
	 */
	private static function replaceKeys(array $data, array $map): array
	{
		foreach ($map as $key => $newKey)
		{
			if (array_key_exists($key, $data))
			{
				$data[$newKey] = $data[$key];
				unset($data[$key]);
			}

			if (isset($data['FIELDS']) && array_key_exists($key, $data['FIELDS']))
			{
				$data['FIELDS'][$newKey] = $data['FIELDS'][$key];
				unset($data['FIELDS'][$key]);
			}
		}

		return $data;
	}

	private static function logAnalytics($action, $handler, $personType, \CRestServer $restServer) : bool
	{
		$code = '';
		$type = '';
		if ($restServer->getAuthType() === \Bitrix\Rest\OAuth\Auth::AUTH_TYPE)
		{
			$app = \Bitrix\Rest\AppTable::getByClientId($restServer->getClientId());
			if ($app['CODE'])
			{
				$code = $app['CODE'];
				$type = 'appCode';
			}
		}
		else
		{
			$code = $restServer->getPasswordId();
			$type = 'webHook';
		}

		if ($code !== '')
		{
			$tag = uniqid($code, true);
			AddEventToStatFile(
				'sale',
				$action,
				$tag,
				$code,
				$type
			);
			AddEventToStatFile(
				'sale',
				$action,
				$tag,
				$handler,
				'handler'
			);
			AddEventToStatFile(
				'sale',
				$action,
				$tag,
				$personType,
				'personType'
			);
		}

		return true;
	}

	private static function hasAccessToPaySystem(array $paySystemData, string $appId = null): bool
	{
		$handlerCode = $paySystemData['ACTION_FILE'];
		if (Manager::isRestHandler($handlerCode))
		{
			$handlerData = self::getHandlerData($handlerCode);
			if ($appId && !empty($handlerData['APP_ID']) && $handlerData['APP_ID'] !== $appId)
			{
				return false;
			}
		}
		else
		{
			return false;
		}

		return true;
	}

	private static function getHandlerData(string $code): ?array
	{
		static $result = [];

		if (!empty($result[$code]))
		{
			return $result[$code];
		}

		$handlerData = Internals\PaySystemRestHandlersTable::getList([
			'filter' => ['CODE' => $code],
			'limit' => 1,
		])->fetch();
		if (is_array($handlerData))
		{
			$result[$code] = $handlerData;
		}

		return $result[$code] ?? null;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit