Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
crmentitycreatorstepper.php
1<?php
2namespace Bitrix\Sale\Update;
3
6use Bitrix\Crm\Order;
7use Bitrix\Crm\Settings;
8use Bitrix\Crm\Timeline;
9use Bitrix\Crm\Order\Matcher;
13
14Loc::loadMessages(__FILE__);
15
23{
25 private $order;
26
32 public function __construct(Order\Order $order)
33 {
34 $this->order = $order;
35 }
36
40 public function create(): Sale\Result
41 {
42 $result = new Sale\Result();
43
44 $contactCompanyCollection = $this->order->getContactCompanyCollection();
45 if ($contactCompanyCollection && $contactCompanyCollection->isEmpty())
46 {
47 $this->addContactCompany();
48 }
49
50 $this->setContactCompanyRequisites();
51
52 if (!$this->isSetResponsible())
53 {
54 $this->setResponsible();
55 }
56
57 $saveOrderResult = $this->order->save();
58 if ($saveOrderResult->isSuccess())
59 {
60 $this->addTimeLines();
61 }
62 else
63 {
64 $result->addErrors($saveOrderResult->getErrors());
65 }
66
67 return $result;
68 }
69
73 private function isSetResponsible(): bool
74 {
75 return (bool)$this->order->getField("RESPONSIBLE_ID");
76 }
77
78 private function setResponsible(): void
79 {
80 $this->order->setFieldNoDemand(
81 "RESPONSIBLE_ID",
82 Settings\OrderSettings::getCurrent()->getDefaultResponsibleId()
83 );
84 }
85
89 private function addContactCompany(): void
90 {
91 $matches = Matcher\EntityMatchManager::getInstance()->match($this->order);
92 if ($matches)
93 {
95 $communication = $this->order->getContactCompanyCollection();
96 if (isset($matches[\CCrmOwnerType::Contact]))
97 {
99 $contact = Order\Contact::create($communication);
100 $contact->setField("ENTITY_ID", $matches[\CCrmOwnerType::Contact]);
101 $contact->setField("IS_PRIMARY", "Y");
102
103 $communication->addItem($contact);
104 }
105
106 if (isset($matches[\CCrmOwnerType::Company]))
107 {
109 $company = Order\Company::create($communication);
110 $company->setField("ENTITY_ID", $matches[\CCrmOwnerType::Company]);
111 $company->setField("IS_PRIMARY", "Y");
112
113 $communication->addItem($company);
114 }
115 }
116 }
117
121 private function setContactCompanyRequisites(): void
122 {
123 $collection = $this->order->getContactCompanyCollection();
124 if (!$collection)
125 {
126 return;
127 }
128
129 $entity = $collection->getPrimaryCompany();
130 if ($entity === null)
131 {
132 $entity = $collection->getPrimaryContact();
133 }
134
135 if ($entity === null)
136 {
137 return;
138 }
139
140 $result = [
141 "MC_REQUISITE_ID" => 0,
142 "MC_BANK_DETAIL_ID" => 0
143 ];
144
145 $requisiteList = $entity->getRequisiteList();
146 if ($requisiteList)
147 {
148 $result["REQUISITE_ID"] = current($requisiteList)["ID"];
149 }
150
151 $bankRequisiteList = $entity->getBankRequisiteList();
152 if ($bankRequisiteList)
153 {
154 $result["BANK_DETAIL_ID"] = current($bankRequisiteList)["ID"];
155 }
156
157 $this->order->setRequisiteLink($result);
158 }
159
160 private function addTimeLines(): void
161 {
162 // add
163 $this->addTimelineEntryOnCreate();
164
165 $historyChanges = $this->getHistoryChanges();
166 foreach ($historyChanges as $historyChange)
167 {
168 // status
169 if ($historyChange["TYPE"] === "ORDER_STATUS_CHANGED")
170 {
171 $this->addTimelineEntryOnStatusModify($historyChange["DATA"]["OLD"], $historyChange["DATA"]["CURRENT"]);
172 }
173 }
174
175 // cancel
176 $this->addTimelineEntryOnCancel();
177 }
178
182 private function addTimelineEntryOnCreate(): void
183 {
184 Timeline\OrderController::getInstance()->onCreate(
185 $this->order->getId(),
186 [
187 "ORDER_FIELDS" => [
188 "ID" => (int)$this->order->getId(),
189 "CREATED_BY" => $this->order->getField("CREATED_BY"),
190 "RESPONSIBLE_ID" => $this->order->getField("RESPONSIBLE_ID"),
191 "DATE_INSERT" => $this->order->getField("DATE_INSERT"),
192 "PRICE" => $this->order->getField("PRICE"),
193 "CURRENCY" => $this->order->getField("CURRENCY")
194 ],
195 "BINDINGS" => [
196 [
197 "ENTITY_TYPE_ID" => \CCrmOwnerType::Order,
198 "ENTITY_ID" => $this->order->getId()
199 ]
200 ],
201 ]
202 );
203 }
204
208 private function addTimelineEntryOnCancel(): void
209 {
210 if ($this->order->getField("CANCELED") !== "Y")
211 {
212 return;
213 }
214
215 $fields = [
216 "ID" => $this->order->getId(),
217 "CANCELED" => $this->order->getField("CANCELED"),
218 ];
219
220 $fields["REASON_CANCELED"] = $this->order->getField("REASON_CANCELED");
221 $fields["EMP_CANCELED_ID"] = $this->order->getField("EMP_CANCELED_ID");
222
223 Timeline\OrderController::getInstance()->onCancel(
224 $this->order->getId(),
225 [
226 "FIELDS" => $fields,
227 "BINDINGS" => [
228 [
229 "ENTITY_TYPE_ID" => \CCrmOwnerType::Order,
230 "ENTITY_ID" => $this->order->getId()
231 ]
232 ],
233 ]
234 );
235 }
236
242 private function addTimelineEntryOnStatusModify($prevStatus, $currentStatus): void
243 {
244 $modifyParams = [
245 "PREVIOUS_FIELDS" => ["STATUS_ID" => $prevStatus],
246 "CURRENT_FIELDS" => [
247 "STATUS_ID" => $currentStatus,
248 "EMP_STATUS_ID" => $this->order->getField("EMP_STATUS_ID")
249 ],
250 "BINDINGS" => [
251 [
252 "ENTITY_TYPE_ID" => \CCrmOwnerType::Order,
253 "ENTITY_ID" => $this->order->getId()
254 ]
255 ],
256 ];
257
258 Timeline\OrderController::getInstance()->onModify($this->order->getId(), $modifyParams);
259 }
260
264 private function getHistoryChanges(): array
265 {
266 $arHistoryData = [];
267
268 $arFilterHistory = ["ORDER_ID" => $this->order->getId()];
269 $arFilterHistory["@TYPE"] = ["ORDER_STATUS_CHANGED"];
270
271 $dbOrderChange = Sale\Internals\OrderChangeTable::getList([
272 "select" => ["*"],
273 "filter" => $arFilterHistory,
274 "order" => [
275 "DATE_CREATE" => "DESC",
276 "ID" => "ASC"
277 ],
278 'limit' => 10,
279 ]);
280 while ($arChangeRecord = $dbOrderChange->fetch())
281 {
282 $arHistoryData[] = $arChangeRecord;
283 }
284
285 Main\Type\Collection::sortByColumn($arHistoryData, ['ID' => SORT_ASC]);
286
287 $dbRes = new \CDBResult();
288 $dbRes->InitFromArray($arHistoryData);
289
290 $result = [];
291 while ($arRes = $dbRes->Fetch())
292 {
293 if (\CheckSerializedData($arRes["DATA"]))
294 {
295 $data = unserialize($arRes["DATA"], ['allowed_classes' => false]);
296 if ($arRes["TYPE"] === "ORDER_STATUS_CHANGED")
297 {
298 $result[] = [
299 "TYPE" => $arRes["TYPE"],
300 "DATA" => [
301 "CURRENT" => $data["STATUS_ID"],
302 "OLD" => $data["OLD_STATUS_ID"],
303 ],
304 ];
305 }
306 }
307 }
308
309 return $result;
310 }
311}
312
320{
321 public const CONTINUE_EXECUTING = true;
322 public const STOP_EXECUTING = false;
323
325 public const IS_SALE_CRM_SITE_MASTER_STUB = "~IS_SALE_CRM_SITE_MASTER_STUB";
326
328 public const ORDER_CONVERT_IS_FINISH = "~ORDER_CONVERT_IS_FINISH";
329
331 public const IS_SALE_CRM_SITE_MASTER_FINISH = "~IS_SALE_CRM_SITE_MASTER_FINISH";
332
333 public const PREFIX_OPTION_ADMIN_PANEL_IS_ENABLED = "~ADMIN_PANEL_IS_ENABLED_FOR_";
334
335 public const IS_CRM_SITE_MASTER_OPENED = "~IS_CRM_SITE_MASTER_OPENED";
336
338 public const WIZARD_SITE_ID = "~CRM_WIZARD_SITE_ID";
339
341 public const STEPPER_PARAMS = "~CRM_ENTITY_CREATOR_STEPPER_PARAMS";
342
343 public const UPDATE_ORDER_CONVERTER_CRM_ERROR_TABLE = "~UPDATE_ORDER_CONVERTER_CRM_ERROR_TABLE";
344
345 public const ORDER_CONVERTER_CRM_ERROR_COUNT = "~ORDER_CONVERTER_CRM_ERROR_COUNT";
346
348 public const MAX_EXECUTION_TIME = 5;
349
351 public const MAX_ORDERS = 100;
352
353 protected static $moduleId = "sale";
354
355 private $orderList = [];
356
357 private $params = [];
358
363 public function execute(array &$result)
364 {
365 if (!Main\Loader::includeModule("crm"))
366 {
368 }
369
370 $this->initParams();
371
372 $this->orderList = self::isUpdateOrder() ? $this->getErrorOrders() : $this->getOrders();
373 if (!$this->orderList)
374 {
377
379
380 if (self::getErrors()->fetch())
381 {
382 $this->addAdminErrorNotify(Loc::getMessage("CRM_ENTITY_CREATOR_STEPPER_ERROR_NOTIFY"));
383 }
384 else
385 {
386 $this->addAdminNormalNotify(
387 Loc::getMessage("CRM_ENTITY_CREATOR_STEPPER_SUCCESS_NOTIFY", [
388 "#ORDER_LINK#" => $this->getPathToOrderList()
389 ])
390 );
391 }
392
394 }
395
396 $this->createCrmEntity();
397
398 $result = [
399 "count" => self::isUpdateOrder() ? $this->getErrorOrderCount() : $this->getOrderCount(),
400 "steps" => $this->params["updated_order_count"],
401 ];
402
404 }
405
406 private function createCrmEntity(): void
407 {
408 $timeStart = Main\Diag\Helper::getCurrentMicrotime();
409 foreach ($this->orderList as $order)
410 {
411 try
412 {
413 $crmEntity = new CrmEntityCreator($order);
414 $resultAdd = $crmEntity->create();
415 if (!$resultAdd->isSuccess())
416 {
417 $errorMessages = $resultAdd->getErrorMessages();
418 $this->setError($order->getId(), implode(" ", $errorMessages));
419 }
420 else
421 {
422 if (self::isUpdateOrder())
423 {
424 $this->deleteError($order->getId());
425 }
426 }
427 }
428 catch (\Exception $ex)
429 {
430 $this->setError($order->getId(), $ex->getMessage());
431 }
432
433 $this->updateParams($order->getId());
434
435 $timeEnd = Main\Diag\Helper::getCurrentMicrotime();
436 if ($timeEnd - $timeStart > self::MAX_EXECUTION_TIME)
437 {
438 break;
439 }
440 }
441 }
442
443 private function initParams(): void
444 {
445 $params = Option::get(self::$moduleId, self::STEPPER_PARAMS, "");
446 if ($params !== "" && \CheckSerializedData($params))
447 {
448 $params = unserialize($params, ['allowed_classes' => false]);
449 }
450
451 $this->params = (\is_array($params) ? $params : []);
452 if (empty($this->params))
453 {
454 $this->params = [
455 "last_order_id" => null,
456 "updated_order_count" => 0
457 ];
458 }
459 }
460
464 private function updateParams($orderId): void
465 {
466 $this->params["last_order_id"] = $orderId;
467 $this->params["updated_order_count"]++;
468
469 Option::set(self::$moduleId, self::STEPPER_PARAMS, serialize($this->params));
470 }
471
475 private function getOrders(): ?array
476 {
477 $parameters = [
478 "order" => ["ID" => "ASC"],
479 "limit" => self::MAX_ORDERS,
480 ];
481 if ($this->params["last_order_id" ] !== null)
482 {
483 $parameters["filter"] = [">ID" => $this->params["last_order_id"]];
484 }
485
486 return Order\Order::loadByFilter($parameters);
487 }
488
489 private function getErrorOrders()
490 {
491 $parameters = [
492 "order" => ["ORDER_ID" => "ASC"],
493 "limit" => self::MAX_ORDERS,
494 ];
495 if ($this->params["last_order_id" ] !== null)
496 {
497 $parameters["filter"] = [">ORDER_ID" => $this->params["last_order_id"]];
498 }
499
500 $errorOrderIdList = [];
501 $orderErrorIterator = self::getErrors($parameters);
502 while($orderError = $orderErrorIterator->fetch())
503 {
504 $errorOrderIdList[] = $orderError["ORDER_ID"];
505 }
506
507 if ($errorOrderIdList)
508 {
509 $parameters = [
510 "filter" => ["ID" => $errorOrderIdList]
511 ];
512
513 $orders = Order\Order::loadByFilter($parameters);
514 $ordersIdList = [];
515 foreach ($orders as $order)
516 {
517 $ordersIdList[] = $order->getId();
518 }
519
520 $diffOrderListId = array_diff($errorOrderIdList, $ordersIdList);
521 foreach ($diffOrderListId as $diffOrderId)
522 {
523 $this->deleteError($diffOrderId);
524 }
525
526 return $orders;
527 }
528
529 return [];
530 }
531
532 private function getOrderCount()
533 {
534 return Order\Order::getList([
535 "select" => ["CNT"],
536 "runtime" => [
537 new Main\Entity\ExpressionField("CNT", "COUNT(*)")
538 ]
539 ])->fetch()["CNT"];
540 }
541
542 private function getErrorOrderCount()
543 {
544 $optionValue = Option::get(self::$moduleId, self::ORDER_CONVERTER_CRM_ERROR_COUNT, false);
545 if ($optionValue === false)
546 {
547 $optionValue = Sale\Internals\OrderConverterCrmErrorTable::getList([
548 "select" => ["CNT"],
549 "runtime" => [
550 new Main\Entity\ExpressionField("CNT", "COUNT(*)")
551 ]
552 ])->fetch()["CNT"];
553
554 Option::set(self::$moduleId, self::ORDER_CONVERTER_CRM_ERROR_COUNT, $optionValue);
555 }
556
557 return $optionValue;
558 }
559
560 public static function setFinishStatus(): void
561 {
562 Option::set(self::$moduleId, self::ORDER_CONVERT_IS_FINISH, "Y");
563 }
564
568 public static function isFinished(): bool
569 {
570 return (Option::get(self::$moduleId, self::ORDER_CONVERT_IS_FINISH, "N") === "Y");
571 }
572
576 private static function isUpdateOrder(): bool
577 {
578 return (Option::get(self::$moduleId, self::UPDATE_ORDER_CONVERTER_CRM_ERROR_TABLE, "N") === "Y");
579 }
580
584 public static function isNeedStub(): bool
585 {
586 $isShow = false;
587 if (Option::get("sale", self::IS_CRM_SITE_MASTER_OPENED, "N") === "Y")
588 {
589 if
590 (
591 Option::get("sale", self::IS_SALE_CRM_SITE_MASTER_STUB, "N") === "Y"
592 && Option::get("sale", self::IS_SALE_CRM_SITE_MASTER_FINISH, "N") === "Y"
593 )
594 {
595 $isShow = true;
596 }
597 }
598 else
599 {
600 $isShow = Main\ModuleManager::isModuleInstalled("crm");
601 }
602
603 if ($isShow)
604 {
605 global $USER;
606 if (Option::get('sale', self::PREFIX_OPTION_ADMIN_PANEL_IS_ENABLED.$USER->GetID()) !== 'Y')
607 {
608 return true;
609 }
610 }
611
612 return false;
613 }
614
618 public static function isAgent(): bool
619 {
620 return (bool)\CAgent::GetList(
621 [],
622 [
623 "NAME" => __CLASS__."::execAgent();"
624 ]
625 )->Fetch();
626 }
627
631 public static function showProgressBar(): void
632 {
633 if (defined("ADMIN_SECTION")
634 || (defined("SITE_TEMPLATE_ID") && SITE_TEMPLATE_ID !== "bitrix24")
635 )
636 {
637 return;
638 }
639
640 if (self::getCrmSiteId() !== SITE_ID)
641 {
642 return;
643 }
644
645 global $APPLICATION;
646
647 $currentPage = $APPLICATION->getCurPage();
648 if ((mb_strpos($currentPage, "/crm/") !== false) || (mb_strpos($currentPage, "/shop/") !== false))
649 {
650 $ids = ["sale" => __CLASS__];
651 $content = self::getHtml($ids, Loc::getMessage("CRM_ENTITY_CREATOR_STEPPER_TITLE"));
652 if ($content)
653 {
654 $APPLICATION->AddViewContent("above_pagetitle", $content);
655 }
656
657 unset($content);
658 }
659 }
660
664 public static function getTitle()
665 {
666 return Loc::getMessage("CRM_ENTITY_CREATOR_STEPPER_TITLE");
667 }
668
669 public static function bindAgent(): void
670 {
671 if (
672 defined("ADMIN_SECTION")
673 || (defined("SITE_TEMPLATE_ID") && SITE_TEMPLATE_ID !== "bitrix24")
674 || (!Main\Loader::includeModule("crm"))
675 )
676 {
677 return;
678 }
679
680 if (self::getCrmSiteId() !== SITE_ID)
681 {
682 return;
683 }
684
685 if (!\CAllCrmInvoice::installExternalEntities())
686 {
687 return;
688 }
689
690 if (
691 !self::isAgent()
692 && !self::isFinished()
693 )
694 {
695 include_once $_SERVER["DOCUMENT_ROOT"].BX_ROOT."/components/bitrix/sale.crm.site.master/tools/sitepatcher.php";
696 $sitePatcher = \Bitrix\Sale\CrmSiteMaster\Tools\SitePatcher::getInstance();
697 $sitePatcher->setCrmUserGroups();
698 $sitePatcher->setCrmGroupRights();
699
700 // delete options
701 \Bitrix\Sale\CrmSiteMaster\Tools\SitePatcher::deleteEmployeesGroupId();
702 \Bitrix\Sale\CrmSiteMaster\Tools\SitePatcher::deleteCompanyDepartmentId();
703 \Bitrix\Sale\CrmSiteMaster\Tools\SitePatcher::retrieveConfig1C();
704
705 // create agent
706 self::bind(5);
707 }
708 }
709
713 public static function registerEventHandler(): void
714 {
715 RegisterModuleDependences("main", "OnEpilog", self::$moduleId, __CLASS__, "showProgressBar", 500);
716 RegisterModuleDependences("main", "OnEpilog", self::$moduleId, __CLASS__, "bindAgent", 500);
717 }
718
722 public static function unregisterEventHandler(): void
723 {
724 UnRegisterModuleDependences("main", "OnEpilog", self::$moduleId, __CLASS__, "showProgressBar");
725 UnRegisterModuleDependences("main", "OnEpilog", self::$moduleId, __CLASS__, "bindAgent");
726 }
727
728 public static function bindAgentOrderUpdate(): void
729 {
730 if (!self::isAgent())
731 {
732 Option::delete(self::$moduleId, ["name" => self::STEPPER_PARAMS]);
733 Option::delete(self::$moduleId, ["name" => self::ORDER_CONVERT_IS_FINISH]);
734
735 Option::set(self::$moduleId, self::UPDATE_ORDER_CONVERTER_CRM_ERROR_TABLE, "Y");
736
737 // create agent
738 self::bind(5);
739 }
740 }
741
745 public static function registerOrderUpdateEventHandler(): void
746 {
747 Option::delete(self::$moduleId, ["name" => self::ORDER_CONVERT_IS_FINISH]);
748 Option::delete(self::$moduleId, ["name" => self::ORDER_CONVERTER_CRM_ERROR_COUNT]);
749
750 RegisterModuleDependences("main", "OnEpilog", self::$moduleId, __CLASS__, "showProgressBar", 500);
751 RegisterModuleDependences("main", "OnEpilog", self::$moduleId, __CLASS__, "bindAgentOrderUpdate", 500);
752 }
753
757 public static function unregisterOrderUpdateEventHandler(): void
758 {
759 UnRegisterModuleDependences("main", "OnEpilog", self::$moduleId, __CLASS__, "showProgressBar");
760 UnRegisterModuleDependences("main", "OnEpilog", self::$moduleId, __CLASS__, "bindAgentOrderUpdate");
761 }
762
767 private function setError($orderId, $errorMessage): void
768 {
769 $orderRow = Sale\Internals\OrderConverterCrmErrorTable::getList([
770 'filter' => ["ORDER_ID" => $orderId],
771 ])->fetch();
772 if (!$orderRow)
773 {
774 $this->addError($orderId, $errorMessage);
775 }
776 else
777 {
778 $this->updateError($orderId, $errorMessage);
779 }
780 }
785 private function addError($orderId, $errorMessage): void
786 {
787 Sale\Internals\OrderConverterCrmErrorTable::add([
788 "ORDER_ID" => $orderId,
789 "ERROR" => $errorMessage
790 ]);
791 }
792
797 private function updateError($orderId, $errorMessage): void
798 {
799 Sale\Internals\OrderConverterCrmErrorTable::update($orderId, [
800 "ERROR" => $errorMessage
801 ]);
802 }
803
807 private function deleteError($orderId): void
808 {
809 $orderRow = Sale\Internals\OrderConverterCrmErrorTable::getList([
810 "select" => ["ID"],
811 "filter" => ["ORDER_ID" => $orderId],
812 ])->fetch();
813 if ($orderRow)
814 {
815 Sale\Internals\OrderConverterCrmErrorTable::delete($orderRow["ID"]);
816 }
817 }
818
822 public static function getErrors(array $parameters = [])
823 {
824 return Sale\Internals\OrderConverterCrmErrorTable::getList($parameters);
825 }
826
830 private function addAdminNormalNotify($message): void
831 {
832 $this->addAdminNotify($message, \CAdminNotify::TYPE_NORMAL);
833 }
834
838 private function addAdminErrorNotify($message): void
839 {
840 $this->addAdminNotify($message, \CAdminNotify::TYPE_ERROR);
841 }
842
848 private function addAdminNotify($message, $notifyType): void
849 {
850 \CAdminNotify::Add([
851 "MODULE_ID" => "sale",
852 "TAG" => "crm_entity_stepper",
853 "MESSAGE" => $message,
854 "NOTIFY_TYPE" => $notifyType,
855 "PUBLIC_SECTION" => "N",
856 ]);
857 }
858
862 private static function getCrmSiteId(): string
863 {
864 return Option::get(self::$moduleId, self::WIZARD_SITE_ID);
865 }
866
870 public function getPathToOrderList(): string
871 {
872 $site = Main\SiteTable::getList([
873 "select" => ["SERVER_NAME"],
874 "filter" => ["=LID" => self::getCrmSiteId()]
875 ])->fetch();
876
877 $siteUrl = (Main\Context::getCurrent()->getRequest()->isHttps() ? "https://" : "http://").$site["SERVER_NAME"];
878 $pathToOderList = Option::get("crm", "path_to_order_list", "/shop/orders/");
879
880 return $siteUrl.$pathToOderList;
881 }
882
886 public static function OnAfterUserLogin($params): void
887 {
888 $value = Option::get('sale', self::PREFIX_OPTION_ADMIN_PANEL_IS_ENABLED.$params['USER_ID'], '');
889 if ($value !== '' && $value !== 'N')
890 {
891 Option::set('sale', self::PREFIX_OPTION_ADMIN_PANEL_IS_ENABLED.$params['USER_ID'], 'N');
892 }
893 }
894}
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static getHtml($ids=array(), $title="")
Definition stepper.php:42