...Человеческий поиск в разработке...
- Модуль: crm
- Путь к файлу: ~/bitrix/modules/crm/classes/general/crm_deal.php
- Класс: \CAllCrmDeal
- Вызов: CAllCrmDeal::Add
public function Add(array &$arFields, $bUpdateSearch = true, $options = array()) { global $DB; if (!is_array($options)) { $options = array(); } $this->LAST_ERROR = ''; $this->checkExceptions = array(); $isRestoration = isset($options['IS_RESTORATION']) && $options['IS_RESTORATION']; if ($this->isUseOperation()) { return $this->getCompatibilityAdapter()->performAdd($arFields, $options); } $userID = isset($options['CURRENT_USER']) ? (int)$options['CURRENT_USER'] : CCrmSecurityHelper::GetCurrentUserID(); if($userID <= 0 && $this->bCheckPermission) { $arFields['RESULT_MESSAGE'] = $this->LAST_ERROR = GetMessage('CRM_PERMISSION_USER_NOT_DEFINED'); return false; } unset($arFields['ID']); if(!($isRestoration && isset($arFields['DATE_CREATE']))) { unset($arFields['DATE_CREATE']); $arFields['~DATE_CREATE'] = $DB->CurrentTimeFunction(); } if(!($isRestoration && isset($arFields['DATE_MODIFY']))) { unset($arFields['DATE_MODIFY']); $arFields['~DATE_MODIFY'] = $DB->CurrentTimeFunction(); } if(!($isRestoration && isset($arFields['MOVED_TIME']))) { unset($arFields['MOVED_TIME']); } if(!($isRestoration && isset($arFields['MOVED_BY_ID']))) { unset($arFields['MOVED_BY_ID']); } if($userID > 0) { if(!(isset($arFields['CREATED_BY_ID']) && $arFields['CREATED_BY_ID'] > 0)) { $arFields['CREATED_BY_ID'] = $userID; } if(!(isset($arFields['MODIFY_BY_ID']) && $arFields['MODIFY_BY_ID'] > 0)) { $arFields['MODIFY_BY_ID'] = $userID; } if(!(isset($arFields['ASSIGNED_BY_ID']) && $arFields['ASSIGNED_BY_ID'] > 0)) { $arFields['ASSIGNED_BY_ID'] = $userID; } } if(!isset($arFields['TITLE']) || !is_string($arFields['TITLE']) || trim($arFields['TITLE']) === '') { $arFields['TITLE'] = self::GetDefaultTitle(); } $fields = self::GetUserFields(); $this->fillEmptyFieldValues($arFields, $fields); if (!$this->CheckFields($arFields, false, $options)) { $result = false; $arFields['RESULT_MESSAGE'] = &$this->LAST_ERROR; } else { if (!isset($arFields['IS_RECURRING'])) { $arFields['IS_RECURRING'] = 'N'; } if (!isset($arFields['MOVED_BY_ID'])) { $arFields['MOVED_BY_ID'] = (int)$userID; } if (!isset($arFields['MOVED_TIME'])) { $arFields['MOVED_TIME'] = (new \Bitrix\Main\Type\DateTime())->toString(); } self::getLastActivityAdapter()->performAdd($arFields, $options); self::getCommentsAdapter()->normalizeFields(null, $arFields); //region Category $categoryID = isset($arFields['CATEGORY_ID']) ? max((int)$arFields['CATEGORY_ID'], 0) : 0; if($categoryID > 0 && !DealCategory::isEnabled($categoryID)) { $categoryID = 0; } $arFields['CATEGORY_ID'] = $categoryID; //endregion //region StageID, SemanticID and IsNew $permissionTypeId = ( $this->bCheckPermission ? Bitrix\Crm\Security\EntityPermissionType::CREATE : Bitrix\Crm\Security\EntityPermissionType::UNDEFINED ); if (!isset($arFields['STAGE_ID']) || (string)$arFields['STAGE_ID'] === '') { $arFields['STAGE_ID'] = self::GetStartStageID($categoryID, $permissionTypeId); } $viewMode = ($options['ITEM_OPTIONS']['VIEW_MODE'] ?? null); $viewModeActivitiesStageId = null; if ($viewMode === ViewMode::MODE_ACTIVITIES) { $viewModeActivitiesStageId = $arFields['STAGE_ID']; $arFields['STAGE_ID'] = self::GetStartStageID($categoryID, $permissionTypeId); } $isStageExist = self::IsStageExists($arFields['STAGE_ID'], $categoryID); $arFields['STAGE_SEMANTIC_ID'] = $isStageExist ? self::GetSemanticID($arFields['STAGE_ID'], $categoryID) : Bitrix\Crm\PhaseSemantics::UNDEFINED ; $arFields['IS_NEW'] = $arFields['STAGE_ID'] === self::GetStartStageID($categoryID) ? 'Y' : 'N'; //endregion $observerIDs = isset($arFields['OBSERVER_IDS']) && is_array($arFields['OBSERVER_IDS']) ? $arFields['OBSERVER_IDS'] : null; unset($arFields['OBSERVER_IDS']); $arAttr = array(); if (!empty($arFields['STAGE_ID'])) { $arAttr['STAGE_ID'] = $arFields['STAGE_ID']; } if (!empty($arFields['OPENED'])) { $arAttr['OPENED'] = $arFields['OPENED']; } if(!empty($observerIDs)) { $arAttr['CONCERNED_USER_IDS'] = $observerIDs; } $permissionEntityType = DealCategory::convertToPermissionEntityType($arFields['CATEGORY_ID']); $sPermission = 'ADD'; if (isset($arFields['PERMISSION'])) { if ($arFields['PERMISSION'] == 'IMPORT') $sPermission = 'IMPORT'; unset($arFields['PERMISSION']); } $assignedByID = (int)$arFields['ASSIGNED_BY_ID']; if($this->bCheckPermission) { $arEntityAttr = self::BuildEntityAttr($userID, $arAttr); $userPerms = $userID == CCrmPerms::GetCurrentUserID() ? $this->cPerms : CCrmPerms::GetUserPermissions($userID); $sEntityPerm = $userPerms->GetPermType($permissionEntityType, $sPermission, $arEntityAttr); if ($sEntityPerm == BX_CRM_PERM_NONE) { $this->LAST_ERROR = GetMessage('CRM_PERMISSION_DENIED'); $arFields['RESULT_MESSAGE'] = &$this->LAST_ERROR; return false; } if ($sEntityPerm == BX_CRM_PERM_SELF && $assignedByID != $userID) { $arFields['ASSIGNED_BY_ID'] = $assignedByID = $userID; } if ($sEntityPerm == BX_CRM_PERM_OPEN && $userID == $assignedByID) { $arFields['OPENED'] = 'Y'; } } $assignedByID = (int)$arFields['ASSIGNED_BY_ID']; $arEntityAttr = self::BuildEntityAttr($assignedByID, $arAttr); $userPerms = $assignedByID == CCrmPerms::GetCurrentUserID() ? $this->cPerms : CCrmPerms::GetUserPermissions($assignedByID); $sEntityPerm = $userPerms->GetPermType($permissionEntityType, $sPermission, $arEntityAttr); self::PrepareEntityAttrs($arEntityAttr, $sEntityPerm); //Prepare currency & exchange rate if(!isset($arFields['CURRENCY_ID'])) { $arFields['CURRENCY_ID'] = CCrmCurrency::GetBaseCurrencyID(); } if(!isset($arFields['EXCH_RATE'])) { $arFields['EXCH_RATE'] = CCrmCurrency::GetExchangeRate($arFields['CURRENCY_ID']); } $arFields = array_merge($arFields, \CCrmAccountingHelper::calculateAccountingData($arFields, [], true)); //Scavenging if(isset($arFields['BEGINDATE']) && (!is_string($arFields['BEGINDATE']) || trim($arFields['BEGINDATE']) === '')) { unset($arFields['BEGINDATE']); } if(isset($arFields['CLOSEDATE']) && (!is_string($arFields['CLOSEDATE']) || trim($arFields['CLOSEDATE']) === '')) { unset($arFields['CLOSEDATE']); } $currentDate = ConvertTimeStamp(time() + \CTimeZone::GetOffset(), 'SHORT', SITE_ID); $arFields['~BEGINDATE'] = $DB->CharToDateFunction( isset($arFields['BEGINDATE']) ? $arFields['BEGINDATE'] : $currentDate, 'SHORT', false ); if(isset($arFields['BEGINDATE'])) { $arFields['__BEGINDATE'] = $arFields['BEGINDATE']; unset($arFields['BEGINDATE']); } $isFinalStage = self::GetStageSemantics($arFields['STAGE_ID'], $categoryID) !== 'process'; $enableCloseDateSync = DealSettings::getCurrent()->isCloseDateSyncEnabled(); if(isset($options['ENABLE_CLOSE_DATE_SYNC']) && is_bool($options['ENABLE_CLOSE_DATE_SYNC'])) { $enableCloseDateSync = $options['ENABLE_CLOSE_DATE_SYNC']; } $arFields['CLOSED'] = $isFinalStage ? 'Y' : 'N'; if($enableCloseDateSync && $isFinalStage) { $arFields['CLOSEDATE'] = $currentDate; $arFields['~CLOSEDATE'] = $DB->CharToDateFunction($currentDate, 'SHORT', false); } elseif($isFinalStage && !isset($arFields['CLOSEDATE'])) { $arFields['CLOSEDATE'] = $currentDate; $arFields['~CLOSEDATE'] = $DB->CharToDateFunction($currentDate, 'SHORT', false); } elseif(isset($arFields['CLOSEDATE'])) { $arFields['~CLOSEDATE'] = $DB->CharToDateFunction($arFields['CLOSEDATE'], 'SHORT', false); } if(isset($arFields['CLOSEDATE'])) { $arFields['__CLOSEDATE'] = $arFields['CLOSEDATE']; unset($arFields['CLOSEDATE']); } //region Preparation of contacts $contactBindings = isset($arFields['CONTACT_BINDINGS']) && is_array($arFields['CONTACT_BINDINGS']) ? $arFields['CONTACT_BINDINGS'] : null; $contactIDs = isset($arFields['CONTACT_IDS']) && is_array($arFields['CONTACT_IDS']) ? $arFields['CONTACT_IDS'] : null; unset($arFields['CONTACT_IDS']); //For backward compatibility only $contactID = isset($arFields['CONTACT_ID']) ? max((int)$arFields['CONTACT_ID'], 0) : null; if($contactID !== null && $contactIDs === null && $contactBindings === null) { $contactIDs = array(); if($contactID > 0) { $contactIDs[] = $contactID; } } unset($arFields['CONTACT_ID']); if(is_array($contactIDs) && !is_array($contactBindings)) { $contactBindings = EntityBinding::prepareEntityBindings( \CCrmOwnerType::Contact, $contactIDs ); EntityBinding::markFirstAsPrimary($contactBindings); } elseif(is_array($contactBindings)) { if(EntityBinding::findPrimaryBinding($contactBindings) === null) { EntityBinding::markFirstAsPrimary($contactBindings); } $contactIDs = EntityBinding::prepareEntityIDs( CCrmOwnerType::Contact, $contactBindings ); } //endregion //region Rise BeforeAdd event $beforeEvents = GetModuleEvents('crm', 'OnBeforeCrmDealAdd'); while ($arEvent = $beforeEvents->Fetch()) { if(ExecuteModuleEventEx($arEvent, array(&$arFields)) === false) { if(isset($arFields['RESULT_MESSAGE'])) { $this->LAST_ERROR = $arFields['RESULT_MESSAGE']; } else { $this->LAST_ERROR = GetMessage('CRM_DEAL_CREATION_CANCELED', array('#NAME#' => $arEvent['TO_NAME'])); $arFields['RESULT_MESSAGE'] = &$this->LAST_ERROR; } return false; } } //endregion if(!isset($arFields['COMPANY_ID'])) { $arFields['COMPANY_ID'] = 0; } unset($arFields['ID']); $this->normalizeEntityFields($arFields); $ID = (int) $DB->Add(self::TABLE_NAME, $arFields, [], 'FILE: '.__FILE__.'
LINE: '.__LINE__); //Append ID to TITLE if required if($ID > 0 && $arFields['TITLE'] === self::GetDefaultTitle()) { $arFields['TITLE'] = self::GetDefaultTitle($ID); $sUpdate = $DB->PrepareUpdate('b_crm_deal', array('TITLE' => $arFields['TITLE'])); if($sUpdate <> '') { $DB->Query("UPDATE b_crm_deal SET {$sUpdate} WHERE ID = {$ID}", false, 'FILE: '.__FILE__.'
LINE: '.__LINE__); }; } if(defined('BX_COMP_MANAGED_CACHE')) { $GLOBALS['CACHE_MANAGER']->CleanDir('b_crm_deal'); } $result = $arFields['ID'] = $ID; //Restore BEGINDATE and CLOSEDATE if(isset($arFields['__BEGINDATE'])) { $arFields['BEGINDATE'] = $arFields['__BEGINDATE']; unset($arFields['__BEGINDATE']); } if(isset($arFields['__CLOSEDATE'])) { $arFields['CLOSEDATE'] = $arFields['__CLOSEDATE']; unset($arFields['__CLOSEDATE']); } //region User Field CCrmEntityHelper::NormalizeUserFields($arFields, self::$sUFEntityID, $GLOBALS['USER_FIELD_MANAGER'], array('IS_NEW' => true)); $GLOBALS['USER_FIELD_MANAGER']->Update(self::$sUFEntityID, $ID, $arFields); //endregion //region Save Observers if(!empty($observerIDs)) { Crm\Observer\ObserverManager::registerBulk($observerIDs, \CCrmOwnerType::Deal, $ID); } //endregion $securityRegisterOptions = (new \Bitrix\Crm\Security\Controller\RegisterOptions()) ->setEntityAttributes($arEntityAttr) ; Crm\Security\Manager::getEntityController(CCrmOwnerType::Deal) ->register($permissionEntityType, $ID, $securityRegisterOptions) ; //region Save contacts if(!empty($contactBindings)) { DealContactTable::bindContacts($ID, $contactBindings); if (isset($GLOBALS['USER']) && !empty($contactIDs)) { CUserOptions::SetOption( 'crm', 'crm_contact_search', array('last_selected' => $contactIDs[count($contactIDs) - 1]) ); } } //endregion if(!empty($contactBindings)) { $arFields['CONTACT_ID'] = EntityBinding::getPrimaryEntityID(CCrmOwnerType::Contact, $contactBindings); } self::SynchronizeCustomerData($ID, $arFields); //Statistics & History --> if ($arFields['IS_RECURRING'] !== 'Y') { DealSumStatisticEntry::register($ID, $arFields); DealInvoiceStatisticEntry::synchronize($ID, $arFields); DealStageHistoryEntry::register($ID, $arFields, array('IS_NEW' => true)); } if(isset($arFields['LEAD_ID']) && $arFields['LEAD_ID'] > 0) { LeadConversionStatisticsEntry::processBindingsChange($arFields['LEAD_ID']); } //<-- Statistics & History if (($options['DISABLE_TIMELINE_CREATION'] ?? null) !== 'Y') { if($isRestoration) { Bitrix\Crm\Timeline\DealController::getInstance()->onRestore($ID, array('FIELDS' => $arFields)); } else { Bitrix\Crm\Timeline\DealController::getInstance()->onCreate( $ID, array( 'FIELDS' => $arFields, 'CONTACT_BINDINGS' => $contactBindings ) ); } } CCrmEntityHelper::registerAdditionalTimelineEvents([ 'entityTypeId' => \CCrmOwnerType::Deal, 'entityId' => $ID, 'fieldsInfo' => static::GetFieldsInfo(), 'previousFields' => [], 'currentFields' => $arFields, 'previousStageSemantics' => Crm\PhaseSemantics::UNDEFINED, 'currentStageSemantics' => $arFields['STAGE_SEMANTIC_ID'] ?? Crm\PhaseSemantics::UNDEFINED, 'options' => $options, 'bindings' => [ 'entityTypeId' => \CCrmOwnerType::Contact, 'previous' => [], 'current' => $contactBindings, ] ]); \Bitrix\Crm\Counter\Monitor::getInstance()->onEntityAdd(CCrmOwnerType::Deal, $arFields); // tracking of entity Tracking\Entity::onAfterAdd(CCrmOwnerType::Deal, $ID, $arFields); //region save parent relations Crm\Service\Container::getInstance()->getParentFieldManager()->saveParentRelationsForIdentifier( new Crm\ItemIdentifier(\CCrmOwnerType::Deal, $ID), $arFields ); //endregion if($bUpdateSearch) { $arFilterTmp = Array('ID' => $ID); if (!$this->bCheckPermission) $arFilterTmp["CHECK_PERMISSIONS"] = "N"; CCrmSearch::UpdateSearch($arFilterTmp, 'DEAL', true); } if (isset($GLOBALS['USER']) && isset($arFields['COMPANY_ID']) && intval($arFields['COMPANY_ID']) > 0) { CUserOptions::SetOption('crm', 'crm_company_search', array('last_selected' => $arFields['COMPANY_ID'])); } //region Search content index Bitrix\Crm\Search\SearchContentBuilderFactory::create( CCrmOwnerType::Deal )->build($ID, ['checkExist' => true]); //endregion self::getCommentsAdapter()->performAdd($arFields, $options); if(isset($options['REGISTER_SONET_EVENT']) && $options['REGISTER_SONET_EVENT'] === true) { $opportunity = round((isset($arFields['OPPORTUNITY']) ? doubleval($arFields['OPPORTUNITY']) : 0.0), 2); $currencyID = isset($arFields['CURRENCY_ID']) ? $arFields['CURRENCY_ID'] : ''; if($currencyID === '') { $currencyID = CCrmCurrency::GetBaseCurrencyID(); } $assignedByID = intval($arFields['ASSIGNED_BY_ID']); $createdByID = intval($arFields['CREATED_BY_ID']); $companyID = (int)$arFields['COMPANY_ID']; $liveFeedFields = array( 'USER_ID' => $createdByID, 'ENTITY_TYPE_ID' => CCrmOwnerType::Deal, 'ENTITY_ID' => $ID, 'TITLE' => GetMessage('CRM_DEAL_EVENT_ADD'), 'MESSAGE' => '', 'PARAMS' => array( 'TITLE' => isset($arFields['TITLE']) ? $arFields['TITLE'] : '', 'STAGE_ID' => isset($arFields['STAGE_ID']) ? $arFields['STAGE_ID'] : '', 'CATEGORY_ID' => isset($arFields['CATEGORY_ID']) ? $arFields['CATEGORY_ID'] : 0, 'OPPORTUNITY' => strval($opportunity), 'CURRENCY_ID' => $currencyID, 'COMPANY_ID' => $companyID, 'CONTACT_ID' => isset($arFields['CONTACT_ID']) ? intval($arFields['CONTACT_ID']) : 0, 'AUTHOR_ID' => intval($arFields['CREATED_BY_ID']), 'RESPONSIBLE_ID' => $assignedByID ) ); //Register contact & company relations $parents = array(); if($companyID > 0) { CCrmLiveFeed::PrepareOwnershipRelations( CCrmOwnerType::Company, array($companyID), $parents ); } if(is_array($contactIDs)) { CCrmLiveFeed::PrepareOwnershipRelations( CCrmOwnerType::Contact, $contactIDs, $parents ); } if(!empty($parents)) { $liveFeedFields['PARENTS'] = array_values($parents); } if (Crm\Settings\Crm::isLiveFeedRecordsGenerationEnabled()) { CCrmSonetSubscription::RegisterSubscription( CCrmOwnerType::Deal, $ID, CCrmSonetSubscriptionType::Responsibility, $assignedByID ); } $logEventID = CCrmLiveFeed::CreateLogEvent($liveFeedFields, CCrmLiveFeedEvent::Add, ['CURRENT_USER' => $userID]); if ( $logEventID !== false && $assignedByID != $createdByID && CModule::IncludeModule("im") ) { $url = CCrmOwnerType::GetEntityShowPath(CCrmOwnerType::Deal, $ID); $serverName = (CMain::IsHTTPS() ? "https" : "http")."://".((defined("SITE_SERVER_NAME") && SITE_SERVER_NAME <> '') ? SITE_SERVER_NAME : COption::GetOptionString("main", "server_name", "")); $arMessageFields = array( "MESSAGE_TYPE" => IM_MESSAGE_SYSTEM, "TO_USER_ID" => $assignedByID, "FROM_USER_ID" => $createdByID, "NOTIFY_TYPE" => IM_NOTIFY_FROM, "NOTIFY_MODULE" => "crm", "LOG_ID" => $logEventID, //"NOTIFY_EVENT" => "deal_add", "NOTIFY_EVENT" => "changeAssignedBy", "NOTIFY_TAG" => "CRM|DEAL_RESPONSIBLE|".$ID, "NOTIFY_MESSAGE" => GetMessage("CRM_DEAL_RESPONSIBLE_IM_NOTIFY", Array("#title#" => "".htmlspecialcharsbx($arFields['TITLE'])."")), "NOTIFY_MESSAGE_OUT" => GetMessage("CRM_DEAL_RESPONSIBLE_IM_NOTIFY", Array("#title#" => htmlspecialcharsbx($arFields['TITLE'])))." (".$serverName.$url.")" ); CIMNotify::Add($arMessageFields); } } //region Rise AfterAdd event $afterEvents = GetModuleEvents('crm', 'OnAfterCrmDealAdd'); while ($arEvent = $afterEvents->Fetch()) { ExecuteModuleEventEx($arEvent, array(&$arFields)); } //endregion if(isset($arFields['ORIGIN_ID']) && $arFields['ORIGIN_ID'] !== '') { $afterEvents = GetModuleEvents('crm', 'OnAfterExternalCrmDealAdd'); while ($arEvent = $afterEvents->Fetch()) { ExecuteModuleEventEx($arEvent, array(&$arFields)); } } if ($ID>0) { if ( $viewMode === ViewMode::MODE_ACTIVITIES && $viewModeActivitiesStageId ) { $deadline = (new Crm\Kanban\EntityActivityDeadline())->getDeadline($viewModeActivitiesStageId); if ($deadline) { \Bitrix\Crm\Activity\Entity\ToDo::createWithDefaultDescription( \CCrmOwnerType::Deal, $ID, $deadline ); } } $item = Crm\Kanban\Entity::getInstance(self::$TYPE_NAME) ->createPullItem($arFields); PullManager::getInstance()->sendItemAddedEvent( $item, [ 'TYPE' => self::$TYPE_NAME, 'CATEGORY_ID' => \CCrmDeal::GetCategoryID($ID), 'SKIP_CURRENT_USER' => ($userID !== 0), ] ); } } return $result; }