Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
saveorderaction.php
1<?php
3
6use Bitrix\Crm;
7use Bitrix\Crm\Order\Manager;
8
16{
17 private ?int $compilationDealId;
18
23 public function run(array $fields)
24 {
25 $checkFieldsResult = $this->checkFields($fields);
26 if (!$checkFieldsResult->isSuccess())
27 {
28 $this->addErrors($checkFieldsResult->getErrors());
29 return null;
30 }
31
32 $saveOrderResult = $this->saveOrder($fields);
33 if ($saveOrderResult->isSuccess())
34 {
35 $saveOrderData = $saveOrderResult->getData();
36
38 $order = $saveOrderData['ORDER'];
39
41 $user = $saveOrderData['USER'];
42
43 return array_merge(
44 Sale\Helpers\Controller\Action\Entity\Order::getAggregateOrder($order),
45 [
46 'USER' => $user,
47 'HASH' => $order->getHash(),
48 ]
49 );
50 }
51
52 $this->addErrors($saveOrderResult->getErrors());
53 return null;
54 }
55
56 private function saveOrder(array $fields)
57 {
58 $result = new Sale\Result();
59
60 $resultData = [];
61
62 $prepareOrderResult = $this->prepareOrder($fields);
63 if ($prepareOrderResult->isSuccess())
64 {
65 $getOrderData = $prepareOrderResult->getData();
66
68 $order = $getOrderData['order'];
69
70 $setUserResult = $this->setUser($order, $fields);
71 if ($setUserResult->isSuccess())
72 {
73 $resultData['USER'] = $setUserResult->getData();
74 }
75 else
76 {
77 $this->fillErrorCollection(
78 $result,
79 $setUserResult->getErrors(),
81 );
82 return $result;
83 }
84
85 $userProfileData = $fields['USER_PROFILE'] ?? null;
86 $setProfileResult = $this->setProfile($order, $userProfileData);
87 if (!$setProfileResult->isSuccess())
88 {
89 $this->fillErrorCollection(
90 $result,
91 $setProfileResult->getErrors(),
93 );
94 return $result;
95 }
96
97 $doFinalActionsResult = $this->doFinalActions($order);
98 if (!$doFinalActionsResult->isSuccess())
99 {
100 $this->fillErrorCollection(
101 $result,
102 $doFinalActionsResult->getErrors(),
104 );
105 return $result;
106 }
107
108 $saveResult = $order->save();
109 if (!$saveResult->isSuccess())
110 {
111 $this->fillErrorCollection(
112 $result,
113 $saveResult->getErrors(),
115 );
116 return $result;
117 }
118
119 if (
120 Main\Loader::includeModule('crm')
121 && class_exists(Crm\Integration\CompilationManager::class)
122 )
123 {
124 if (isset($this->compilationDealId))
125 {
126 Manager::copyOrderProductsToDeal($order, $this->compilationDealId);
127 }
128
129 Crm\Integration\CompilationManager::sendOrderBoundEvent($order);
130 Crm\Integration\CompilationManager::sendToCompilationDealTimeline($order);
131 }
132
133 $resultData['ORDER'] = $order;
134 $result->setData($resultData);
135 }
136 else
137 {
138 $result->addErrors($prepareOrderResult->getErrors());
139 }
140
141 return $result;
142 }
143
144 private function checkFields(array $fields): Sale\Result
145 {
146 $result = new Sale\Result();
147
148 if (empty($fields['SITE_ID']))
149 {
150 $result->addError(
151 new Main\Error(
152 'siteId not found',
154 )
155 );
156 }
157
158 if (empty($fields['FUSER_ID']) || (int)$fields['FUSER_ID'] <= 0)
159 {
160 $result->addError(
161 new Main\Error(
162 'fuserId not found',
164 )
165 );
166 }
167
168 if (empty($fields['PERSON_TYPE_ID']))
169 {
170 $result->addError(
171 new Main\Error(
172 'personTypeId not found',
174 )
175 );
176 }
177
178 return $result;
179 }
180
181 private function prepareOrder(array $fields): Sale\Result
182 {
183 $result = new Sale\Result();
184
185 $order = $this->createOrder($fields['SITE_ID']);
186
187 $personTypeId = (int)$fields['PERSON_TYPE_ID'];
188 $setPersonTypeIdResult = $this->setPersonTypeId($order, $personTypeId);
189 if (!$setPersonTypeIdResult->isSuccess())
190 {
191 $this->fillErrorCollection(
192 $result,
193 $setPersonTypeIdResult->getErrors(),
195 );
196 return $result;
197 }
198
199 if (!empty($fields['TRADING_PLATFORM_ID']))
200 {
201 $tradingPlatformId = $fields['TRADING_PLATFORM_ID'];
202 $setTradeBindingResult = $this->setTradeBinding($order, $tradingPlatformId);
203 if (!$setTradeBindingResult->isSuccess())
204 {
205 $this->fillErrorCollection(
206 $result,
207 $setTradeBindingResult->getErrors(),
209 );
210 return $result;
211 }
212 }
213
214 $properties = $fields['PROPERTIES'] ?? null;
215 if ($properties)
216 {
217 $setPropertiesResult = $this->setProperties($order, $properties);
218 if (!$setPropertiesResult->isSuccess())
219 {
220 $this->fillErrorCollection(
221 $result,
222 $setPropertiesResult->getErrors(),
224 );
225 return $result;
226 }
227 }
228
229 $setBasketResult = $this->setBasket($order, $fields['FUSER_ID']);
230 if (!$setBasketResult->isSuccess())
231 {
232 $this->fillErrorCollection(
233 $result,
234 $setBasketResult->getErrors(),
236 );
237 return $result;
238 }
239
240 if (
241 Main\Loader::includeModule('crm')
242 && class_exists(Crm\Integration\CompilationManager::class)
243 )
244 {
245 $this->compilationDealId = Crm\Integration\CompilationManager::processOrderForCompilation($order);
246 }
247
248 $result->setData(['order' => $order]);
249 return $result;
250 }
251
252 private function createOrder(string $siteId): Sale\Order
253 {
254 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
256 $orderClassName = $registry->getOrderClassName();
257
258 return $orderClassName::create($siteId);
259 }
260
261 private function setPersonTypeId(Sale\Order $order, int $personTypeId): Sale\Result
262 {
263 $result = new Sale\Result();
264
265 $setPersonTypeIdResult = $order->setPersonTypeId($personTypeId);
266 if (!$setPersonTypeIdResult->isSuccess())
267 {
268 $result->addErrors($setPersonTypeIdResult->getErrors());
269 }
270
271 return $result;
272 }
273
274 private function setProperties(Sale\Order $order, array $properties): Sale\Result
275 {
276 $result = new Sale\Result();
277
278 $propertyCollection = $order->getPropertyCollection();
279 $setValuesResult = $propertyCollection->setValuesFromPost(['PROPERTIES' => $properties], []);
280 if (!$setValuesResult->isSuccess())
281 {
282 foreach ($setValuesResult->getErrors() as $error)
283 {
284 $result->addError(new Main\Error($error->getMessage()));
285 }
286 }
287
289 foreach ($propertyCollection as $propValue)
290 {
291 if ($propValue->isUtil())
292 {
293 continue;
294 }
295
296 $verifyResult = $propValue->verify();
297 if (!$verifyResult->isSuccess())
298 {
299 foreach ($verifyResult->getErrors() as $error)
300 {
301 $result->addError(
302 new Main\Error($error->getMessage(), 0, ['id' => $propValue->getPropertyId()])
303 );
304 }
305 }
306
307 $checkRequiredValueResult = $propValue->checkRequiredValue($propValue->getPropertyId(), $propValue->getValue());
308 if (!$checkRequiredValueResult->isSuccess())
309 {
310 foreach ($checkRequiredValueResult->getErrors() as $error)
311 {
312 $result->addError(
313 new Main\Error($error->getMessage(), 0, ['id' => $propValue->getPropertyId()])
314 );
315 }
316 }
317 }
318
319 return $result;
320 }
321
322 private function setBasket(Sale\Order $order, int $fuserId): Sale\Result
323 {
324 $result = new Sale\Result();
325
326 $registry = Sale\Registry::getInstance(Sale\Registry::REGISTRY_TYPE_ORDER);
327
329 $basketClassName = $registry->getBasketClassName();
330 $basket = $basketClassName::loadItemsForFUser($fuserId, $order->getSiteId());
331
332 $refreshResult = $basket->refresh();
333 if ($refreshResult->isSuccess())
334 {
335 $saveBasketResult = $basket->save();
336 if (!$saveBasketResult->isSuccess())
337 {
338 $result->addErrors($refreshResult->getErrors());
339 }
340 }
341 else
342 {
343 $result->addErrors($refreshResult->getErrors());
344 }
345
346 if (!$result->isSuccess(true))
347 {
348 return $result;
349 }
350
351 $availableBasket = $basket->getOrderableItems();
352 if ($availableBasket && !$availableBasket->isEmpty())
353 {
354 $setBasketResult = $order->setBasket($availableBasket);
355 if (!$setBasketResult->isSuccess())
356 {
357 $result->addErrors($setBasketResult->getErrors());
358 }
359 }
360 elseif ($availableBasket)
361 {
362 $result->addError(new Main\Error('basket is empty'));
363 }
364 else
365 {
366 $result->addError(new Main\Error('basket is null'));
367 }
368
369 return $result;
370 }
371
372 private function setUser(Sale\Order $order, array $fields): Sale\Result
373 {
374 $result = new Sale\Result();
375
376 $isNewUser = false;
377
378 if ((int)$fields['USER_ID'] > 0)
379 {
380 $userId = (int)$fields['USER_ID'];
381
382 if ($this->isLandingShop($order) && Main\Loader::includeModule('crm'))
383 {
384 Crm\Service\Sale\Order\BuyerService::getInstance()->attachUserToBuyers($userId);
385 }
386 }
387 else
388 {
389 $properties = [];
390
392 foreach ($order->getPropertyCollection() as $property)
393 {
394 $properties[$property->getPropertyId()] = $property->getValue();
395 }
396
397 $userProps = Sale\Property::getMeaningfulValues($order->getPersonTypeId(), $properties);
398
399 $email = $userProps['EMAIL'] ?? '';
400 $phone = $userProps['PHONE'] ?? '';
401
402 $userId = $this->searchExistingUser($email, $phone);
403 if (!$userId)
404 {
405 $registerNewUserResult = $this->registerNewUser($order, $userProps);
406 if ($registerNewUserResult->isSuccess())
407 {
408 $registerNewUserData = $registerNewUserResult->getData();
409 $userId = $registerNewUserData['userId'];
410
411 $isNewUser = true;
412 }
413 else
414 {
415 $result->addErrors($registerNewUserResult->getErrors());
416 return $result;
417 }
418 }
419 }
420
421 if (!$userId)
422 {
423 $result->addError(new Main\Error('User not found'));
424 return $result;
425 }
426
427 $order->setFieldNoDemand('USER_ID', $userId);
428
429 $result->setData([
430 'ID' => $userId,
431 'IS_NEW' => $isNewUser,
432 ]);
433
434 return $result;
435 }
436
437 private function searchExistingUser(string $email, string $phone): ?int
438 {
439 $existingUserId = null;
440
441 if (!empty($email))
442 {
443 $res = Main\UserTable::getRow([
444 'filter' => [
445 '=ACTIVE' => 'Y',
446 '=EMAIL' => $email,
447 ],
448 'select' => ['ID'],
449 ]);
450 if (isset($res['ID']))
451 {
452 $existingUserId = (int)$res['ID'];
453 }
454 }
455
456 if (!$existingUserId && !empty($phone))
457 {
458 $normalizedPhone = NormalizePhone($phone);
459 $normalizedPhoneForRegistration = Main\UserPhoneAuthTable::normalizePhoneNumber($phone);
460
461 if (!empty($normalizedPhone))
462 {
463 $res = Main\UserTable::getRow([
464 'filter' => [
465 'ACTIVE' => 'Y',
466 [
467 'LOGIC' => 'OR',
468 '=PHONE_AUTH.PHONE_NUMBER' => $normalizedPhoneForRegistration,
469 '=PERSONAL_PHONE' => $normalizedPhone,
470 '=PERSONAL_MOBILE' => $normalizedPhone,
471 ],
472 ],
473 'select' => ['ID'],
474 ]);
475 if (isset($res['ID']))
476 {
477 $existingUserId = (int)$res['ID'];
478 }
479 }
480 }
481
482 return $existingUserId;
483 }
484
485 private function registerNewUser(Sale\Order $order, array $userProps): Sale\Result
486 {
487 $result = new Sale\Result();
488
489 $siteId = $order->getSiteId();
490
491 $userData = $this->generateUserData($userProps);
492 $fields = [
493 'LOGIN' => $userData['NEW_LOGIN'],
494 'NAME' => $userData['NEW_NAME'],
495 'LAST_NAME' => $userData['NEW_LAST_NAME'],
496 'PASSWORD' => $userData['NEW_PASSWORD'],
497 'CONFIRM_PASSWORD' => $userData['NEW_PASSWORD_CONFIRM'],
498 'EMAIL' => $userData['NEW_EMAIL'],
499 'GROUP_ID' => $userData['GROUP_ID'],
500 'ACTIVE' => 'Y',
501 'LID' => $siteId,
502 'PERSONAL_PHONE' => isset($userProps['PHONE']) ? NormalizePhone($userProps['PHONE']) : '',
503 'PERSONAL_ZIP' => $userProps['ZIP'] ?? '',
504 'PERSONAL_STREET' => $userProps['ADDRESS'] ?? '',
505 ];
506
507 $userPhoneAuth = Main\Config\Option::get('main', 'new_user_phone_auth', 'N', $siteId) === 'Y';
508 if ($userPhoneAuth)
509 {
510 $normalizedPhoneForRegistration = '';
511 if (!empty($userProps['PHONE']))
512 {
513 $normalizedPhoneForRegistration = Main\UserPhoneAuthTable::normalizePhoneNumber($userProps['PHONE']);
514 }
515
516 $fields['PHONE_NUMBER'] = $normalizedPhoneForRegistration;
517 }
518
519 if ($this->isLandingShop($order) && Main\Loader::includeModule('crm'))
520 {
521 $fields['GROUP_ID'] = Crm\Order\BuyerGroup::getDefaultGroups();
522 $fields['EXTERNAL_AUTH_ID'] = 'shop';
523 $fields['UF_DEPARTMENT'] = [];
524 if (!empty($userData['NEW_EMAIL']))
525 {
526 $fields['LOGIN'] = $userData['NEW_EMAIL'];
527 }
528 }
529
530 $user = new \CUser();
531 $addResult = $user->Add($fields);
532 if ((int)$addResult <= 0)
533 {
534 $errors = explode('<br>', $user->LAST_ERROR);
535 TrimArr($errors, true);
536 foreach ($errors as $error)
537 {
538 $result->addError(new Main\Error($error));
539 }
540 }
541 else
542 {
543 $result->setData(['userId' => $addResult]);
544 }
545
546 return $result;
547 }
548
549 private function generateUserData(array $userProps = []): array
550 {
551 $userEmail = isset($userProps['EMAIL']) ? trim((string)$userProps['EMAIL']) : '';
552 $newLogin = $userEmail;
553
554 if (empty($userEmail))
555 {
556 $newEmail = false;
557
558 $normalizedPhone = NormalizePhone($userProps['PHONE']);
559 if (!empty($normalizedPhone))
560 {
561 $newLogin = $normalizedPhone;
562 }
563 }
564 else
565 {
566 $newEmail = $userEmail;
567 }
568
569 if (empty($newLogin))
570 {
571 $newLogin = Main\Security\Random::getString(5).random_int(0, 99999);
572 }
573
574 $pos = mb_strpos($newLogin, '@');
575 if ($pos !== false)
576 {
577 $newLogin = mb_substr($newLogin, 0, $pos);
578 }
579
580 if (mb_strlen($newLogin) > 47)
581 {
582 $newLogin = mb_substr($newLogin, 0, 47);
583 }
584
585 $newLogin = str_pad($newLogin, 3, '_');
586
587 $dbUserLogin = \CUser::GetByLogin($newLogin);
588 if ($userLoginResult = $dbUserLogin->Fetch())
589 {
590 do
591 {
592 $newLoginTmp = $newLogin.random_int(0, 99999);
593 $dbUserLogin = \CUser::GetByLogin($newLoginTmp);
594 }
595 while ($userLoginResult = $dbUserLogin->Fetch());
596
597 $newLogin = $newLoginTmp;
598 }
599
600 $newName = '';
601 $newLastName = '';
602
603 $payerName = isset($userProps['PAYER']) ? trim((string)$userProps['PAYER']) : '';
604 if (!empty($payerName))
605 {
606 $payerName = preg_replace('/\s{2,}/', ' ', $payerName);
607 $nameParts = explode(' ', $payerName);
608 if (isset($nameParts[1]))
609 {
610 $newName = $nameParts[1];
611 $newLastName = $nameParts[0];
612 }
613 else
614 {
615 $newName = $nameParts[0];
616 }
617 }
618
619 $groupIds = [];
620
621 $defaultGroups = Main\Config\Option::get('main', 'new_user_registration_def_group', '');
622 if (!empty($defaultGroups))
623 {
624 $groupIds = explode(',', $defaultGroups);
625 }
626
627 $newPassword = \CUser::GeneratePasswordByPolicy($groupIds);
628
629 return [
630 'NEW_EMAIL' => $newEmail,
631 'NEW_LOGIN' => $newLogin,
632 'NEW_NAME' => $newName,
633 'NEW_LAST_NAME' => $newLastName,
634 'NEW_PASSWORD' => $newPassword,
635 'NEW_PASSWORD_CONFIRM' => $newPassword,
636 'GROUP_ID' => $groupIds,
637 ];
638 }
639
640 private function doFinalActions(Sale\Order $order): Sale\Result
641 {
642 $result = new Sale\Result();
643
644 $hasMeaningfulFields = $order->hasMeaningfulField();
645 $doFinalActionResult = $order->doFinalAction($hasMeaningfulFields);
646
647 if (!$doFinalActionResult->isSuccess())
648 {
649 $result->addErrors($doFinalActionResult->getErrors());
650 }
651
652 return $result;
653 }
654
655 private function setTradeBinding(Sale\Order $order, $tradingPlatformId): Sale\Result
656 {
657 $result = new Sale\Result();
658
659 $platform = Sale\TradingPlatform\Manager::getList([
660 'select' => ['ID'],
661 'filter' => [
662 '=ID' => $tradingPlatformId,
663 ],
664 ])->fetch();
665 if ($platform)
666 {
667 $collection = $order->getTradeBindingCollection();
668
670 $binding = $collection->createItem();
671 $setFieldResult = $binding->setFields([
672 'TRADING_PLATFORM_ID' => $tradingPlatformId,
673 ]);
674
675 if (!$setFieldResult->isSuccess())
676 {
677 $result->addErrors($setFieldResult->getErrors());
678 }
679 }
680 else
681 {
682 $result->addError(
683 new Main\Error('Trading platform with id:"'.$tradingPlatformId.' not found"')
684 );
685 }
686
687 return $result;
688 }
689
690 private function setProfile(Sale\Order $order, array $profileFields = null): Sale\Result
691 {
692 $result = new Sale\Result();
693
694 $profileId = $profileFields['ID'] ?? 0;
695 $profileName = $profileFields['NAME'] ?? '';
696
697 $properties = [];
699 foreach ($order->getPropertyCollection() as $property)
700 {
701 $properties[$property->getPropertyId()] = $property->getValue();
702 }
703
704 $errors = [];
705 \CSaleOrderUserProps::DoSaveUserProfile(
706 $order->getUserId(),
707 $profileId,
708 $profileName,
709 $order->getPersonTypeId(),
710 $properties,
711 $errors
712 );
713
714 foreach ($errors as $error)
715 {
716 $result->addError(new Main\Error($error['TEXT']));
717 }
718
719 return $result;
720 }
721
722 private function isLandingShop(Sale\Order $order): bool
723 {
725 foreach ($order->getTradeBindingCollection() as $tradingItem)
726 {
727 $platformId = $tradingItem->getField('TRADING_PLATFORM_ID');
728 $platform = Sale\TradingPlatform\Manager::getObjectById($platformId);
729 if ($platform instanceof Sale\TradingPlatform\Landing\Landing)
730 {
731 return true;
732 }
733 }
734
735 return false;
736 }
737
743 private function fillErrorCollection(Sale\Result $result, array $errors, $code): void
744 {
745 foreach ($errors as $error)
746 {
747 $result->addError(new Main\Error($error->getMessage(), $code, $error->getCustomData()));
748 }
749 }
750}
addErrors(array $errors)
Definition action.php:213