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/sale/lib/controller/action/entity/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/cvetdv.ru/bitrix/modules/sale/lib/controller/action/entity/saveorderaction.php
<?php
namespace Bitrix\Sale\Controller\Action\Entity;

use Bitrix\Main;
use Bitrix\Sale;
use Bitrix\Crm;
use Bitrix\Crm\Order\Manager;

/**
 * Class SaveOrderAction
 * @package Bitrix\Sale\Controller\Action\Entity
 * @example BX.ajax.runAction("sale.entity.saveOrder", { data: { fields: { siteId:'s1', [userId:1, personTypeId:1] properties: {...}}}});
 * @internal
 */
final class SaveOrderAction extends Sale\Controller\Action\BaseAction
{
	private ?int $compilationDealId;

	/**
	 * @param array $fields
	 * @return array|null
	 */
	public function run(array $fields)
	{
		$checkFieldsResult = $this->checkFields($fields);
		if (!$checkFieldsResult->isSuccess())
		{
			$this->addErrors($checkFieldsResult->getErrors());
			return null;
		}

		$saveOrderResult = $this->saveOrder($fields);
		if ($saveOrderResult->isSuccess())
		{
			$saveOrderData = $saveOrderResult->getData();

			/** @var Sale\Order $order */
			$order = $saveOrderData['ORDER'];

			/** @var array $user */
			$user = $saveOrderData['USER'];

			return array_merge(
				Sale\Helpers\Controller\Action\Entity\Order::getAggregateOrder($order),
				[
					'USER' => $user,
					'HASH' => $order->getHash(),
				]
			);
		}

		$this->addErrors($saveOrderResult->getErrors());
		return null;
	}

	private function saveOrder(array $fields)
	{
		$result = new Sale\Result();

		$resultData = [];

		$prepareOrderResult = $this->prepareOrder($fields);
		if ($prepareOrderResult->isSuccess())
		{
			$getOrderData = $prepareOrderResult->getData();

			/** @var Sale\Order $order */
			$order = $getOrderData['order'];

			$setUserResult = $this->setUser($order, $fields);
			if ($setUserResult->isSuccess())
			{
				$resultData['USER'] = $setUserResult->getData();
			}
			else
			{
				$this->fillErrorCollection(
					$result,
					$setUserResult->getErrors(),
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_SET_USER
				);
				return $result;
			}

			$userProfileData = $fields['USER_PROFILE'] ?? null;
			$setProfileResult = $this->setProfile($order, $userProfileData);
			if (!$setProfileResult->isSuccess())
			{
				$this->fillErrorCollection(
					$result,
					$setProfileResult->getErrors(),
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_SET_PROFILE
				);
				return $result;
			}

			$doFinalActionsResult = $this->doFinalActions($order);
			if (!$doFinalActionsResult->isSuccess())
			{
				$this->fillErrorCollection(
					$result,
					$doFinalActionsResult->getErrors(),
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_FINAL_ACTIONS
				);
				return $result;
			}

			$saveResult = $order->save();
			if (!$saveResult->isSuccess())
			{
				$this->fillErrorCollection(
					$result,
					$saveResult->getErrors(),
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_SAVE
				);
				return $result;
			}

			if (
				Main\Loader::includeModule('crm')
				&& class_exists(Crm\Integration\CompilationManager::class)
			)
			{
				if (isset($this->compilationDealId))
				{
					Manager::copyOrderProductsToDeal($order, $this->compilationDealId);
				}

				Crm\Integration\CompilationManager::sendOrderBoundEvent($order);
				Crm\Integration\CompilationManager::sendToCompilationDealTimeline($order);
			}

			$resultData['ORDER'] = $order;
			$result->setData($resultData);
		}
		else
		{
			$result->addErrors($prepareOrderResult->getErrors());
		}

		return $result;
	}

	private function checkFields(array $fields): Sale\Result
	{
		$result = new Sale\Result();

		if (empty($fields['SITE_ID']))
		{
			$result->addError(
				new Main\Error(
					'siteId not found',
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_SITE_ID_NOT_FOUND
				)
			);
		}

		if (empty($fields['FUSER_ID']) || (int)$fields['FUSER_ID'] <= 0)
		{
			$result->addError(
				new Main\Error(
					'fuserId not found',
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_FUSER_ID_NOT_FOUND
				)
			);
		}

		if (empty($fields['PERSON_TYPE_ID']))
		{
			$result->addError(
				new Main\Error(
					'personTypeId not found',
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_PERSON_TYPE_ID_NOT_FOUND
				)
			);
		}

		return $result;
	}

	private function prepareOrder(array $fields): Sale\Result
	{
		$result = new Sale\Result();

		$order = $this->createOrder($fields['SITE_ID']);

		$personTypeId = (int)$fields['PERSON_TYPE_ID'];
		$setPersonTypeIdResult = $this->setPersonTypeId($order, $personTypeId);
		if (!$setPersonTypeIdResult->isSuccess())
		{
			$this->fillErrorCollection(
				$result,
				$setPersonTypeIdResult->getErrors(),
				Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_SET_PERSON_TYPE_ID
			);
			return $result;
		}

		if (!empty($fields['TRADING_PLATFORM_ID']))
		{
			$tradingPlatformId = $fields['TRADING_PLATFORM_ID'];
			$setTradeBindingResult = $this->setTradeBinding($order, $tradingPlatformId);
			if (!$setTradeBindingResult->isSuccess())
			{
				$this->fillErrorCollection(
					$result,
					$setTradeBindingResult->getErrors(),
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_SET_TRADE_BINDINGS
				);
				return $result;
			}
		}

		$properties = $fields['PROPERTIES'] ?? null;
		if ($properties)
		{
			$setPropertiesResult = $this->setProperties($order, $properties);
			if (!$setPropertiesResult->isSuccess())
			{
				$this->fillErrorCollection(
					$result,
					$setPropertiesResult->getErrors(),
					Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_SET_PROPERTIES
				);
				return $result;
			}
		}

		$setBasketResult = $this->setBasket($order, $fields['FUSER_ID']);
		if (!$setBasketResult->isSuccess())
		{
			$this->fillErrorCollection(
				$result,
				$setBasketResult->getErrors(),
				Sale\Controller\ErrorEnumeration::SAVE_ORDER_ACTION_SET_BASKET
			);
			return $result;
		}

		if (
			Main\Loader::includeModule('crm')
			&& class_exists(Crm\Integration\CompilationManager::class)
		)
		{
			$this->compilationDealId = Crm\Integration\CompilationManager::processOrderForCompilation($order);
		}

		$result->setData(['order' => $order]);
		return $result;
	}

	private function createOrder(string $siteId): Sale\Order
	{
		$registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
		/** @var Sale\Order $orderClassName */
		$orderClassName = $registry->getOrderClassName();

		return $orderClassName::create($siteId);
	}

	private function setPersonTypeId(Sale\Order $order, int $personTypeId): Sale\Result
	{
		$result = new Sale\Result();

		$setPersonTypeIdResult = $order->setPersonTypeId($personTypeId);
		if (!$setPersonTypeIdResult->isSuccess())
		{
			$result->addErrors($setPersonTypeIdResult->getErrors());
		}

		return $result;
	}

	private function setProperties(Sale\Order $order, array $properties): Sale\Result
	{
		$result = new Sale\Result();

		$propertyCollection = $order->getPropertyCollection();
		$setValuesResult = $propertyCollection->setValuesFromPost(['PROPERTIES' => $properties], []);
		if (!$setValuesResult->isSuccess())
		{
			foreach ($setValuesResult->getErrors() as $error)
			{
				$result->addError(new Main\Error($error->getMessage()));
			}
		}

		/** @var Sale\PropertyValue $propValue */
		foreach ($propertyCollection as $propValue)
		{
			if ($propValue->isUtil())
			{
				continue;
			}

			$verifyResult = $propValue->verify();
			if (!$verifyResult->isSuccess())
			{
				foreach ($verifyResult->getErrors() as $error)
				{
					$result->addError(
						new Main\Error($error->getMessage(), 0, ['id' => $propValue->getPropertyId()])
					);
				}
			}

			$checkRequiredValueResult = $propValue->checkRequiredValue($propValue->getPropertyId(), $propValue->getValue());
			if (!$checkRequiredValueResult->isSuccess())
			{
				foreach ($checkRequiredValueResult->getErrors() as $error)
				{
					$result->addError(
						new Main\Error($error->getMessage(), 0, ['id' => $propValue->getPropertyId()])
					);
				}
			}
		}

		return $result;
	}

	private function setBasket(Sale\Order $order, int $fuserId): Sale\Result
	{
		$result = new Sale\Result();

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

		/** @var Sale\Basket $basketClassName */
		$basketClassName = $registry->getBasketClassName();
		$basket = $basketClassName::loadItemsForFUser($fuserId, $order->getSiteId());

		$refreshResult = $basket->refresh();
		if ($refreshResult->isSuccess())
		{
			$saveBasketResult = $basket->save();
			if (!$saveBasketResult->isSuccess())
			{
				$result->addErrors($refreshResult->getErrors());
			}
		}
		else
		{
			$result->addErrors($refreshResult->getErrors());
		}

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

		$availableBasket = $basket->getOrderableItems();
		if ($availableBasket && !$availableBasket->isEmpty())
		{
			$setBasketResult = $order->setBasket($availableBasket);
			if (!$setBasketResult->isSuccess())
			{
				$result->addErrors($setBasketResult->getErrors());
			}
		}
		elseif ($availableBasket)
		{
			$result->addError(new Main\Error('basket is empty'));
		}
		else
		{
			$result->addError(new Main\Error('basket is null'));
		}

		return $result;
	}

	private function setUser(Sale\Order $order, array $fields): Sale\Result
	{
		$result = new Sale\Result();

		$isNewUser = false;

		if ((int)($fields['USER_ID'] ?? 0) > 0)
		{
			$userId = (int)$fields['USER_ID'];

			if ($this->isLandingShop($order) && Main\Loader::includeModule('crm'))
			{
				Crm\Service\Sale\Order\BuyerService::getInstance()->attachUserToBuyers($userId);
			}
		}
		else
		{
			$properties = [];

			/** @var Sale\PropertyValue $property */
			foreach ($order->getPropertyCollection() as $property)
			{
				$properties[$property->getPropertyId()] = $property->getValue();
			}

			$userProps = Sale\Property::getMeaningfulValues($order->getPersonTypeId(), $properties);

			$email = $userProps['EMAIL'] ?? '';
			$phone = $userProps['PHONE'] ?? '';

			$userId = $this->searchExistingUser($email, $phone);
			if (!$userId)
			{
				$registerNewUserResult = $this->registerNewUser($order, $userProps);
				if ($registerNewUserResult->isSuccess())
				{
					$registerNewUserData = $registerNewUserResult->getData();
					$userId = $registerNewUserData['userId'];

					$isNewUser = true;
				}
				else
				{
					$result->addErrors($registerNewUserResult->getErrors());
					return $result;
				}
			}
		}

		if (!$userId)
		{
			$result->addError(new Main\Error('User not found'));
			return $result;
		}

		$order->setFieldNoDemand('USER_ID', $userId);

		$result->setData([
			'ID' => $userId,
			'IS_NEW' => $isNewUser,
		]);

		return $result;
	}

	private function searchExistingUser(string $email, string $phone): ?int
	{
		$existingUserId = null;

		if (!empty($email))
		{
			$res = Main\UserTable::getRow([
				'filter' => [
					'=ACTIVE' => 'Y',
					'=EMAIL' => $email,
				],
				'select' => ['ID'],
			]);
			if (isset($res['ID']))
			{
				$existingUserId = (int)$res['ID'];
			}
		}

		if (!$existingUserId && !empty($phone))
		{
			$normalizedPhone = NormalizePhone($phone);
			$normalizedPhoneForRegistration = Main\UserPhoneAuthTable::normalizePhoneNumber($phone);

			if (!empty($normalizedPhone))
			{
				$res = Main\UserTable::getRow([
					'filter' => [
						'ACTIVE' => 'Y',
						[
							'LOGIC' => 'OR',
							'=PHONE_AUTH.PHONE_NUMBER' => $normalizedPhoneForRegistration,
							'=PERSONAL_PHONE' => $normalizedPhone,
							'=PERSONAL_MOBILE' => $normalizedPhone,
						],
					],
					'select' => ['ID'],
				]);
				if (isset($res['ID']))
				{
					$existingUserId = (int)$res['ID'];
				}
			}
		}

		return $existingUserId;
	}

	private function registerNewUser(Sale\Order $order, array $userProps): Sale\Result
	{
		$result = new Sale\Result();

		$siteId = $order->getSiteId();

		$userData = $this->generateUserData($userProps);
		$fields = [
			'LOGIN' => $userData['NEW_LOGIN'],
			'NAME' => $userData['NEW_NAME'],
			'LAST_NAME' => $userData['NEW_LAST_NAME'],
			'PASSWORD' => $userData['NEW_PASSWORD'],
			'CONFIRM_PASSWORD' => $userData['NEW_PASSWORD_CONFIRM'],
			'EMAIL' => $userData['NEW_EMAIL'],
			'GROUP_ID' => $userData['GROUP_ID'],
			'ACTIVE' => 'Y',
			'LID' => $siteId,
			'PERSONAL_PHONE' => isset($userProps['PHONE']) ? NormalizePhone($userProps['PHONE']) : '',
			'PERSONAL_ZIP' => $userProps['ZIP'] ?? '',
			'PERSONAL_STREET' => $userProps['ADDRESS'] ?? '',
		];

		$userPhoneAuth = Main\Config\Option::get('main', 'new_user_phone_auth', 'N', $siteId) === 'Y';
		if ($userPhoneAuth)
		{
			$normalizedPhoneForRegistration = '';
			if (!empty($userProps['PHONE']))
			{
				$normalizedPhoneForRegistration = Main\UserPhoneAuthTable::normalizePhoneNumber($userProps['PHONE']);
			}

			$fields['PHONE_NUMBER'] = $normalizedPhoneForRegistration;
		}

		if ($this->isLandingShop($order) && Main\Loader::includeModule('crm'))
		{
			$fields['GROUP_ID'] = Crm\Order\BuyerGroup::getDefaultGroups();
			$fields['EXTERNAL_AUTH_ID'] = 'shop';
			$fields['UF_DEPARTMENT'] = [];
			if (!empty($userData['NEW_EMAIL']))
			{
				$fields['LOGIN'] = $userData['NEW_EMAIL'];
			}
		}

		$user = new \CUser();
		$addResult = $user->Add($fields);
		if ((int)$addResult <= 0)
		{
			$errors = explode('<br>', $user->LAST_ERROR);
			TrimArr($errors, true);
			foreach ($errors as $error)
			{
				$result->addError(new Main\Error($error));
			}
		}
		else
		{
			$result->setData(['userId' => $addResult]);
		}

		return $result;
	}

	private function generateUserData(array $userProps = []): array
	{
		$userEmail = isset($userProps['EMAIL']) ? trim((string)$userProps['EMAIL']) : '';
		$newLogin = $userEmail;

		if (empty($userEmail))
		{
			$newEmail = false;

			$normalizedPhone = NormalizePhone($userProps['PHONE']);
			if (!empty($normalizedPhone))
			{
				$newLogin = $normalizedPhone;
			}
		}
		else
		{
			$newEmail = $userEmail;
		}

		if (empty($newLogin))
		{
			$newLogin = Main\Security\Random::getString(5).random_int(0, 99999);
		}

		$pos = mb_strpos($newLogin, '@');
		if ($pos !== false)
		{
			$newLogin = mb_substr($newLogin, 0, $pos);
		}

		if (mb_strlen($newLogin) > 47)
		{
			$newLogin = mb_substr($newLogin, 0, 47);
		}

		$newLogin = str_pad($newLogin, 3, '_');

		$dbUserLogin = \CUser::GetByLogin($newLogin);
		if ($userLoginResult = $dbUserLogin->Fetch())
		{
			do
			{
				$newLoginTmp = $newLogin.random_int(0, 99999);
				$dbUserLogin = \CUser::GetByLogin($newLoginTmp);
			}
			while ($userLoginResult = $dbUserLogin->Fetch());

			$newLogin = $newLoginTmp;
		}

		$newName = '';
		$newLastName = '';

		$payerName = isset($userProps['PAYER']) ? trim((string)$userProps['PAYER']) : '';
		if (!empty($payerName))
		{
			$payerName = preg_replace('/\s{2,}/', ' ', $payerName);
			$nameParts = explode(' ', $payerName);
			if (isset($nameParts[1]))
			{
				$newName = $nameParts[1];
				$newLastName = $nameParts[0];
			}
			else
			{
				$newName = $nameParts[0];
			}
		}

		$groupIds = [];

		$defaultGroups = Main\Config\Option::get('main', 'new_user_registration_def_group', '');
		if (!empty($defaultGroups))
		{
			$groupIds = explode(',', $defaultGroups);
		}

		$newPassword = \CUser::GeneratePasswordByPolicy($groupIds);

		return [
			'NEW_EMAIL' => $newEmail,
			'NEW_LOGIN' => $newLogin,
			'NEW_NAME' => $newName,
			'NEW_LAST_NAME' => $newLastName,
			'NEW_PASSWORD' => $newPassword,
			'NEW_PASSWORD_CONFIRM' => $newPassword,
			'GROUP_ID' => $groupIds,
		];
	}

	private function doFinalActions(Sale\Order $order): Sale\Result
	{
		$result = new Sale\Result();

		$hasMeaningfulFields = $order->hasMeaningfulField();
		$doFinalActionResult = $order->doFinalAction($hasMeaningfulFields);

		if (!$doFinalActionResult->isSuccess())
		{
			$result->addErrors($doFinalActionResult->getErrors());
		}

		return $result;
	}

	private function setTradeBinding(Sale\Order $order, $tradingPlatformId): Sale\Result
	{
		$result = new Sale\Result();

		$platform = Sale\TradingPlatform\Manager::getList([
			'select' => ['ID'],
			'filter' => [
				'=ID' => $tradingPlatformId,
			],
		])->fetch();
		if ($platform)
		{
			$collection = $order->getTradeBindingCollection();

			/** @var Sale\TradeBindingEntity $binding */
			$binding = $collection->createItem();
			$setFieldResult = $binding->setFields([
				'TRADING_PLATFORM_ID' => $tradingPlatformId,
			]);

			if (!$setFieldResult->isSuccess())
			{
				$result->addErrors($setFieldResult->getErrors());
			}
		}
		else
		{
			$result->addError(
				new Main\Error('Trading platform with id:"'.$tradingPlatformId.' not found"')
			);
		}

		return $result;
	}

	private function setProfile(Sale\Order $order, array $profileFields = null): Sale\Result
	{
		$result = new Sale\Result();

		$profileId = $profileFields['ID'] ?? 0;
		$profileName = $profileFields['NAME'] ?? '';

		$properties = [];
		/** @var Sale\PropertyValue $property */
		foreach ($order->getPropertyCollection() as $property)
		{
			$properties[$property->getPropertyId()] = $property->getValue();
		}

		$errors = [];
		\CSaleOrderUserProps::DoSaveUserProfile(
			$order->getUserId(),
			$profileId,
			$profileName,
			$order->getPersonTypeId(),
			$properties,
			$errors
		);

		foreach ($errors as $error)
		{
			$result->addError(new Main\Error($error['TEXT']));
		}

		return $result;
	}

	private function isLandingShop(Sale\Order $order): bool
	{
		/** @var Sale\TradeBindingEntity $tradingItem */
		foreach ($order->getTradeBindingCollection() as $tradingItem)
		{
			$platformId = $tradingItem->getField('TRADING_PLATFORM_ID');
			$platform = Sale\TradingPlatform\Manager::getObjectById($platformId);
			if ($platform instanceof Sale\TradingPlatform\Landing\Landing)
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * @param Sale\Result $result
	 * @param Main\Error[] $errors
	 * @param $code
	 */
	private function fillErrorCollection(Sale\Result $result, array $errors, $code): void
	{
		foreach ($errors as $error)
		{
			$result->addError(new Main\Error($error->getMessage(), $code, $error->getCustomData()));
		}
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit