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 : |
<?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())); } } }