public function Add($arFields, &$arRecalculated = false, $siteId = SITE_ID, $options = array())
{
/** @global \CDatabase $DB */
/** @global \CMain $APPLICATION */
/** @var CApplicationException $ex */
global $DB, $APPLICATION;
if(!CModule::IncludeModule('sale'))
{
$this->LAST_ERROR = GetMessage('CRM_MODULE_SALE_NOT_INSTALLED');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
return false;
}
if(!is_array($options))
{
$options = array();
}
$bRecalculate = is_array($arRecalculated);
$orderID = false;
$tmpOrderId = (intval($arFields['ID']) <= 0) ? 0 : $arFields['ID'];
if (isset($arFields['ID']))
{
unset($arFields['ID']);
}
$arPrevOrder = ($tmpOrderId !== 0) ? CCrmInvoice::GetByID($tmpOrderId, $this->bCheckPermission) : null;
$userId = isset($options['CURRENT_USER'])
? (int)$options['CURRENT_USER'] : CCrmSecurityHelper::GetCurrentUserID();
if (!isset($arFields['RESPONSIBLE_ID']) || (int)$arFields['RESPONSIBLE_ID'] <= 0)
{
if (is_array($arPrevOrder) && isset($arPrevOrder['RESPONSIBLE_ID']) && intval($arPrevOrder['RESPONSIBLE_ID']) > 0)
$arFields['RESPONSIBLE_ID'] = $arPrevOrder['RESPONSIBLE_ID'];
else
$arFields['RESPONSIBLE_ID'] = $userId;
}
$orderStatus = '';
if (isset($arFields['STATUS_ID']))
{
$orderStatus = $arFields['STATUS_ID'];
unset($arFields['STATUS_ID']);
}
else
{
$arFields['STATUS_ID'] = self::GetDefaultStatusId();
}
// prepare entity permissions
$arAttr = [];
if (!empty($arFields['OPENED']))
{
$arAttr['OPENED'] = $arFields['OPENED'];
}
$sPermission = ($tmpOrderId > 0) ? 'WRITE' : 'ADD';
if($this->bCheckPermission)
{
$arEntityAttr = self::BuildEntityAttr($userId, $arAttr);
$userPerms = ($userId == CCrmPerms::GetCurrentUserID()) ? $this->cPerms : CCrmPerms::GetUserPermissions($userId);
$sEntityPerm = $userPerms->GetPermType(self::$TYPE_NAME, $sPermission, $arEntityAttr);
if ($sEntityPerm == BX_CRM_PERM_NONE)
{
$this->LAST_ERROR = GetMessage('CRM_PERMISSION_DENIED');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
return false;
}
$responsibleID = intval($arFields['RESPONSIBLE_ID']);
if ($tmpOrderId === 0 && $sEntityPerm == BX_CRM_PERM_SELF && $responsibleID != $userId)
{
$arFields['RESPONSIBLE_ID'] = $userId;
}
if ($sEntityPerm == BX_CRM_PERM_OPEN && $userId == $responsibleID)
{
$arFields['OPENED'] = 'Y';
}
}
$responsibleID = intval($arFields['RESPONSIBLE_ID']);
$arEntityAttr = self::BuildEntityAttr($responsibleID, $arAttr);
$userPerms = ($responsibleID == CCrmPerms::GetCurrentUserID()) ? $this->cPerms : CCrmPerms::GetUserPermissions($responsibleID);
$sEntityPerm = $userPerms->GetPermType(self::$TYPE_NAME, $sPermission, $arEntityAttr);
$this->PrepareEntityAttrs($arEntityAttr, $sEntityPerm);
// date fields
if ($tmpOrderId === 0)
{
$arFields['~DATE_BILL'] = $DB->CharToDateFunction(
isset($arFields['DATE_BILL']) && $arFields['DATE_BILL'] !== '' ?
$arFields['DATE_BILL'] : ConvertTimeStamp(time() + CTimeZone::GetOffset(), 'SHORT', SITE_ID),
'SHORT',
false
);
}
else if(isset($arFields['DATE_BILL']) && $arFields['DATE_BILL'] !== '')
{
$arFields['~DATE_BILL'] = $DB->CharToDateFunction($arFields['DATE_BILL'], 'SHORT', false);
}
unset($arFields['DATE_BILL']);
if(array_key_exists('DATE_PAY_BEFORE', $arFields))
{
$dateValue = $arFields['DATE_PAY_BEFORE'];
if ($dateValue instanceof Main\Type\DateTime || $dateValue instanceof Main\Type\Date)
{
$dateValue = (string)$dateValue;
}
if (is_string($dateValue) && $dateValue !== '')
{
$arFields['~DATE_PAY_BEFORE'] = $DB->CharToDateFunction($dateValue, 'SHORT', false);
unset($arFields['DATE_PAY_BEFORE']);
}
else
{
$arFields['DATE_PAY_BEFORE'] = '';
}
unset($dateValue);
}
$paidStateCanceled = false;
if ($tmpOrderId > 0 && is_array($arPrevOrder) && !$bRecalculate
&& isset($arPrevOrder['STATUS_ID']) && $arPrevOrder['STATUS_ID'] === 'P'
&& isset($arPrevOrder['PAYED']) && $arPrevOrder['PAYED'] === 'Y')
{
if (!Compatible\Helper::payOrder($tmpOrderId, false))
{
$this->LAST_ERROR = GetMessage('CRM_INVOICE_ERR_CANCEL_PAID_STATE');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
return false;
}
$paidStateCanceled = true;
}
if ($tmpOrderId !== 0 && !isset($arFields['PRODUCT_ROWS']) && !isset($arFields['INVOICE_PROPERTIES']))
{
if (!isset($arFields['ID']))
$arFields['ID'] = $tmpOrderId;
if (!empty($orderStatus))
$arFields['STATUS_ID'] = $orderStatus;
foreach (GetModuleEvents('crm', 'OnBeforeCrmInvoiceUpdate', true) as $arEvent)
{
if(ExecuteModuleEventEx($arEvent, array(&$arFields)) === false)
{
$errMsg = '';
if(isset($arFields['RESULT_MESSAGE']))
{
$errMsg = trim(strval($arFields['RESULT_MESSAGE']));
}
else if ($ex = $APPLICATION->GetException())
{
$errMsg = trim(strval($ex->GetString()));
}
if ($errMsg === '')
{
$this->LAST_ERROR = GetMessage('CRM_INVOICE_UPDATE_CANCELED', array('#NAME#' => $arEvent['TO_NAME']));
}
else
{
$this->LAST_ERROR = $errMsg;
}
unset($errMsg);
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
if ($paidStateCanceled)
{
Compatible\Helper::payOrder($tmpOrderId, true);
}
return false;
}
}
unset($arFields['ID'], $arFields['STATUS_ID']);
if(!is_array($arPrevOrder))
{
$this->LAST_ERROR = GetMessage('CRM_INVOICE_ERR_NOT_FOUND', array('#INVOICE_ID#' => $tmpOrderId));
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
if ($paidStateCanceled)
{
Compatible\Helper::payOrder($tmpOrderId, true);
}
return false;
}
$prevResponsibleID = isset($arPrevOrder['RESPONSIBLE_ID']) ? intval($arPrevOrder['RESPONSIBLE_ID']) : 0;
$responsibleID = isset($arFields['RESPONSIBLE_ID']) ? intval($arFields['RESPONSIBLE_ID']) : 0;
// simple update order fields
$simpleFields = $arFields;
$userFields = $GLOBALS['USER_FIELD_MANAGER']->GetUserFields(self::$sUFEntityID);
if (is_array($userFields))
{
foreach(array_keys($userFields) as $fieldName)
{
if (array_key_exists($fieldName, $simpleFields))
unset($simpleFields[$fieldName]);
}
}
if (is_array($simpleFields) && !empty($simpleFields))
$orderID = Compatible\Helper::Update($tmpOrderId, $simpleFields);
unset($simpleFields, $userFields);
// update user fields
CCrmEntityHelper::NormalizeUserFields($arFields, self::$sUFEntityID, $GLOBALS['USER_FIELD_MANAGER'], array('IS_NEW' => false));
$GLOBALS['USER_FIELD_MANAGER']->Update(self::$sUFEntityID, $tmpOrderId, $arFields);
$registerSonetEvent = isset($options['REGISTER_SONET_EVENT']) && $options['REGISTER_SONET_EVENT'] === true;
if(is_int($orderID) && $orderID > 0)
{
if($registerSonetEvent)
{
$newDealID = isset($arFields['UF_DEAL_ID']) ? intval($arFields['UF_DEAL_ID']) : 0;
$oldDealID = isset($arPrevOrder['UF_DEAL_ID']) ? intval($arPrevOrder['UF_DEAL_ID']) : 0;
$newCompanyID = isset($arFields['UF_COMPANY_ID']) ? intval($arFields['UF_COMPANY_ID']) : 0;
$oldCompanyID = isset($arPrevOrder['UF_COMPANY_ID']) ? intval($arPrevOrder['UF_COMPANY_ID']) : 0;
$newContactID = isset($arFields['UF_CONTACT_ID']) ? intval($arFields['UF_CONTACT_ID']) : 0;
$oldContactID = isset($arPrevOrder['UF_CONTACT_ID']) ? intval($arPrevOrder['UF_CONTACT_ID']) : 0;
$parents = array();
$parentsChanged = $newDealID !== $oldDealID || $newCompanyID !== $oldCompanyID || $newContactID !== $oldContactID;
if($parentsChanged)
{
if($newDealID > 0)
{
$parents[] = array(
'ENTITY_TYPE_ID' => CCrmOwnerType::Deal,
'ENTITY_ID' => $newDealID
);
}
if($newCompanyID > 0)
{
$parents[] = array(
'ENTITY_TYPE_ID' => CCrmOwnerType::Company,
'ENTITY_ID' => $newCompanyID
);
}
if($newContactID > 0)
{
$parents[] = array(
'ENTITY_TYPE_ID' => CCrmOwnerType::Contact,
'ENTITY_ID' => $newContactID
);
}
}
$oldOrderStatus = isset($arPrevOrder['STATUS_ID']) ? $arPrevOrder['STATUS_ID'] : '';
self::SynchronizeLiveFeedEvent(
$orderID,
array(
'PROCESS_PARENTS' => $parentsChanged,
'PARENTS' => $parents,
'REFRESH_DATE' => $orderStatus !== $oldOrderStatus,
'START_RESPONSIBLE_ID' => $prevResponsibleID,
'FINAL_RESPONSIBLE_ID' => $responsibleID,
'TOPIC' => isset($arPrevOrder['ORDER_TOPIC']) ? $arPrevOrder['ORDER_TOPIC'] : $orderID
)
);
}
if (
$responsibleID !== $prevResponsibleID
&& Settings\Crm::isLiveFeedRecordsGenerationEnabled()
)
{
CCrmSonetSubscription::ReplaceSubscriptionByEntity(
CCrmOwnerType::Invoice,
$orderID,
CCrmSonetSubscriptionType::Responsibility,
$responsibleID,
$prevResponsibleID,
$registerSonetEvent
);
}
}
}
else
{
if ($tmpOrderId === 0 && !$bRecalculate)
{
if (!empty($orderStatus))
$arFields['STATUS_ID'] = $orderStatus;
foreach (GetModuleEvents('crm', 'OnBeforeCrmInvoiceAdd', true) as $arEvent)
{
if(ExecuteModuleEventEx($arEvent, array(&$arFields)) === false)
{
$errMsg = '';
if(isset($arFields['RESULT_MESSAGE']))
{
$errMsg = trim(strval($arFields['RESULT_MESSAGE']));
}
else if ($ex = $APPLICATION->GetException())
{
$errMsg = trim(strval($ex->GetString()));
}
if ($errMsg === '')
{
$this->LAST_ERROR = GetMessage('CRM_INVOICE_CREATION_CANCELED', array('#NAME#' => $arEvent['TO_NAME']));
}
else
{
$this->LAST_ERROR = $errMsg;
}
unset($errMsg);
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
if ($paidStateCanceled)
{
Compatible\Helper::payOrder($tmpOrderId, true);
}
return false;
}
}
unset($arFields['STATUS_ID']);
}
else if ($tmpOrderId !== 0 && !$bRecalculate)
{
if (!isset($arFields['ID']))
$arFields['ID'] = $tmpOrderId;
if (!empty($orderStatus))
$arFields['STATUS_ID'] = $orderStatus;
foreach (GetModuleEvents('crm', 'OnBeforeCrmInvoiceUpdate', true) as $arEvent)
{
if(ExecuteModuleEventEx($arEvent, array(&$arFields)) === false)
{
$errMsg = '';
if(isset($arFields['RESULT_MESSAGE']))
{
$errMsg = trim(strval($arFields['RESULT_MESSAGE']));
}
else if ($ex = $APPLICATION->GetException())
{
$errMsg = trim(strval($ex->GetString()));
}
if ($errMsg === '')
{
$this->LAST_ERROR = GetMessage('CRM_INVOICE_UPDATE_CANCELED', array('#NAME#' => $arEvent['TO_NAME']));
}
else
{
$this->LAST_ERROR = $errMsg;
}
unset($errMsg);
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
if ($paidStateCanceled)
{
Compatible\Helper::payOrder($tmpOrderId, true);
}
return false;
}
}
unset($arFields['ID'], $arFields['STATUS_ID']);
}
// check product rows
if (!isset($arFields['PRODUCT_ROWS']) ||
!is_array($arFields['PRODUCT_ROWS']) ||
count($arFields['PRODUCT_ROWS']) <= 0)
{
$this->LAST_ERROR = GetMessage('CRM_ERROR_EMPTY_INVOICE_SPEC');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
if ($paidStateCanceled)
{
Compatible\Helper::payOrder($tmpOrderId, true);
}
return false;
}
$arProduct = $arFields['PRODUCT_ROWS'];
// prepare shopping cart data
//
// get xml_id fields
$catalogXmlId = CCrmCatalog::GetDefaultCatalogXmlId();
$arNewProducts = array();
$bGetBasketXmlIds = false;
foreach ($arProduct as &$productRow)
{
if (!isset($productRow['ID']))
{
$productRow['ID'] = 0;
}
if (intval($productRow['ID']) === 0 && isset($productRow['PRODUCT_ID']))
{
$arNewProducts[] = $productRow['PRODUCT_ID'];
}
else
{
$bGetBasketXmlIds = true;
}
}
unset($productRow);
$arXmlIds = array();
$oldProductRows = null;
if ($bGetBasketXmlIds && intval($tmpOrderId) > 0)
{
$oldProductRows = CCrmInvoice::GetProductRows($tmpOrderId);
if (count($oldProductRows) > 0)
{
foreach ($oldProductRows as $row)
{
$arXmlIds[intval($row['ID'])][$row['PRODUCT_ID']] = array(
'CATALOG_XML_ID' => $row['CATALOG_XML_ID'],
'PRODUCT_XML_ID' => $row['PRODUCT_XML_ID']
);
}
unset($row);
}
}
unset($bGetBasketXmlIds);
if (count($arNewProducts) > 0)
{
$dbRes = CCrmProduct::GetList(array(), array('ID' => $arNewProducts), array('ID', 'XML_ID'));
while ($row = $dbRes->Fetch())
{
$arXmlIds[0][$row['ID']] = array(
'CATALOG_XML_ID' => $catalogXmlId,
'PRODUCT_XML_ID' => $row['XML_ID']
);
}
unset($dbRes, $row);
}
unset($arNewProducts, $arOldProducts);
// products without measures
$productMeasures = array();
$productId = 0;
$productIds = array();
foreach ($arProduct as $productRow)
{
$productId = intval($productRow['PRODUCT_ID']);
if ($productId > 0
&& (!array_key_exists('MEASURE_CODE', $productRow) || intval($productRow['MEASURE_CODE']) <= 0))
{
$productIds[] = $productId;
}
}
unset($productId, $productRow);
if (count($productIds) > 0)
$productMeasures = \Bitrix\Crm\Measure::getProductMeasures($productIds);
unset($productIds);
$currencyId = CCrmInvoice::GetCurrencyID($siteId);
$i = 0;
$defaultMeasure = null;
$oldProductRowsById = null;
foreach ($arProduct as &$productRow)
{
$productXmlId = $catalogXmlId = null;
$rowIndex = intval($productRow['ID']);
$productId = $productRow['PRODUCT_ID'];
$isCustomized = (isset($productRow['CUSTOMIZED']) && $productRow['CUSTOMIZED'] === 'Y');
$productRow['MODULE'] = $productRow['PRODUCT_PROVIDER_CLASS'] = '';
if($productId > 0)
{
if (!$isCustomized)
{
$productRow['MODULE'] = 'catalog';
$productRow['PRODUCT_PROVIDER_CLASS'] = 'CCatalogProductProvider';
}
if (is_array($arXmlIds[$rowIndex])
&& isset($arXmlIds[$rowIndex][$productId]))
{
$catalogXmlId = $arXmlIds[$rowIndex][$productId]['CATALOG_XML_ID'];
$productXmlId = $arXmlIds[$rowIndex][$productId]['PRODUCT_XML_ID'];
}
$productRow['CATALOG_XML_ID'] = $catalogXmlId;
$productRow['PRODUCT_XML_ID'] = $productXmlId;
}
else
{
$productRow["PRODUCT_XML_ID"] = "CRM-".\Bitrix\Main\Security\Random::getString(8, true);
$ri = new \Bitrix\Main\Type\RandomSequence($productRow["PRODUCT_XML_ID"]);
$productRow["PRODUCT_ID"] = $ri->rand(1000000, 9999999);
$productRow['CATALOG_XML_ID'] = '';
}
if($isCustomized)
$productRow['CUSTOM_PRICE'] = 'Y';
if (isset($productRow['PRODUCT_NAME']))
{
$productRow['NAME'] = $productRow['PRODUCT_NAME'];
unset($productRow['PRODUCT_NAME']);
}
if (isset($productRow['PRICE']))
$productRow['PRICE_DEFAULT'] = $productRow['PRICE'];
if (!isset($productRow['CURRENCY']))
$productRow['CURRENCY'] = $currencyId;
// measures
$bRefreshMeasureName = false;
if (!array_key_exists('MEASURE_CODE', $productRow) || intval($productRow['MEASURE_CODE'] <= 0))
{
if ($oldProductRows === null && $tmpOrderId > 0)
{
$oldProductRows = CCrmInvoice::GetProductRows($tmpOrderId);
}
if (is_array($oldProductRows) && count($oldProductRows) > 0 && $oldProductRowsById === null)
{
$oldProductRowsById = array();
foreach ($oldProductRows as $row)
$oldProductRowsById[intval($row['ID'])] = $row;
unset($row);
}
if (is_array($oldProductRowsById) && isset($oldProductRowsById[$rowIndex]))
{
$row = $oldProductRowsById[$rowIndex];
if (intval($productId) === intval($row['PRODUCT_ID']))
{
if (isset($row['MEASURE_CODE']))
$productRow['MEASURE_CODE'] = $row['MEASURE_CODE'];
if (isset($row['MEASURE_NAME']))
$productRow['MEASURE_NAME'] = $row['MEASURE_NAME'];
else
$bRefreshMeasureName = true;
unset($row);
}
}
}
if (!isset($productRow['MEASURE_CODE']) || intval($productRow['MEASURE_CODE']) <= 0)
{
if ($productId > 0 && isset($productMeasures[$productId]))
{
$measure = is_array($productMeasures[$productId][0]) ? $productMeasures[$productId][0] : null;
if (is_array($measure))
{
if (isset($measure['CODE']))
$productRow['MEASURE_CODE'] = $measure['CODE'];
if (isset($measure['SYMBOL']))
$productRow['MEASURE_NAME'] = $measure['SYMBOL'];
}
unset($measure);
}
}
if (!isset($productRow['MEASURE_CODE']) || intval($productRow['MEASURE_CODE']) <= 0)
{
if ($defaultMeasure === null)
$defaultMeasure = \Bitrix\Crm\Measure::getDefaultMeasure();
if (is_array($defaultMeasure))
{
$productRow['MEASURE_CODE'] = $defaultMeasure['CODE'];
$productRow['MEASURE_NAME'] = $defaultMeasure['SYMBOL'];
}
}
if (isset($productRow['MEASURE_CODE'])
&& intval($productRow['MEASURE_CODE']) > 0
&& (
$bRefreshMeasureName ||
!array_key_exists('MEASURE_NAME', $productRow)
|| empty($productRow['MEASURE_NAME'])
)
)
{
$measure = \Bitrix\Crm\Measure::getMeasureByCode($productRow['MEASURE_CODE']);
if (is_array($measure) && isset($measure['SYMBOL']))
$productRow['MEASURE_NAME'] = $measure['SYMBOL'];
unset($measure);
}
$i++;
}
unset($productRow, $productMeasures, $catalogXmlId, $productXmlId);
$arOrderProductPrice = self::__fGetUserShoppingCart($arProduct, $siteId, 'N');
foreach ($arOrderProductPrice as &$arItem) // tmp hack not to update basket quantity data from catalog
{
$arItem["ID_TMP"] = $arItem["ID"];
$arItem["NAME_TMP"] = $arItem["NAME"];
unset($arItem["ID"]);
}
unset($arItem);
// user id for order
$saleUserId = intval(CSaleUser::GetAnonymousUserID());
if ($saleUserId <= 0)
{
$this->LAST_ERROR = GetMessage('CRM_INVOICE_ERR_GET_ANONYMOUS_ID');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
return false;
}
$arErrors = array();
$arShoppingCart = Compatible\BasketHelper::doGetUserShoppingCart(
$siteId, $saleUserId, $arOrderProductPrice, $arErrors, $tmpOrderId, true
);
if (!is_array($arShoppingCart) || count($arShoppingCart) === 0)
{
$this->LAST_ERROR = GetMessage('CRM_ERROR_EMPTY_INVOICE_SPEC');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
return false;
}
foreach ($arShoppingCart as $key => &$arItem)
{
$arItem["ID"] = $arItem["ID_TMP"];
$arItem["NAME"] = $arItem["NAME_TMP"];
unset($arItem["NAME_TMP"], $arItem["ID_TMP"]);
//$arShoppingCart[$key]["ID"] = $arItem["ID"];
}
unset($key, $arItem);
//
// person type
$arPersonTypes = CCrmPaySystem::getPersonTypeIDs();
if (!isset($arPersonTypes['COMPANY']) || !isset($arPersonTypes['CONTACT']))
{
$this->LAST_ERROR = GetMessage('CRM_INVOICE_ERR_PERSON_TYPES_INCORRECT');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
if ($paidStateCanceled)
{
Compatible\Helper::payOrder($tmpOrderId, true);
}
return false;
}
$personTypeId = isset($arFields['PERSON_TYPE_ID']) ? (int)$arFields['PERSON_TYPE_ID'] : 0;
if (isset($arFields['UF_COMPANY_ID']) && intval($arFields['UF_COMPANY_ID']) > 0)
$personTypeId = (int)$arPersonTypes['COMPANY'];
else if (isset($arFields['UF_CONTACT_ID']) && intval($arFields['UF_CONTACT_ID']) > 0)
$personTypeId = (int)$arPersonTypes['CONTACT'];
if ($personTypeId !== intval($arPersonTypes['COMPANY']) && $personTypeId !== intval($arPersonTypes['CONTACT']))
{
$this->LAST_ERROR = GetMessage(
'CRM_INVOICE_ERR_INVALID_PERSON_TYPE_ID',
array(
'#CONTACT#' => $arPersonTypes['CONTACT'],
'#COMPANY#' => $arPersonTypes['COMPANY']
)
);
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
if ($paidStateCanceled)
{
Compatible\Helper::payOrder($tmpOrderId, true);
}
return false;
}
$arFields['PERSON_TYPE_ID'] = $personTypeId;
// preparing order to save
//
$arOrderPropsValues = array();
if (isset($arFields['INVOICE_PROPERTIES']) && is_array($arFields['INVOICE_PROPERTIES']) && count($arFields['INVOICE_PROPERTIES']) > 0)
$arOrderPropsValues = $arFields['INVOICE_PROPERTIES'];
if (isset($arFields['INVOICE_PROPERTIES']))
unset($arFields['INVOICE_PROPERTIES']);
if (count($arOrderPropsValues) <= 0)
{
$this->LAST_ERROR = GetMessage('CRM_INVOICE_ERR_EMPTY_INVOICE_PROPS');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
return false;
}
$deliveryId = null;
$paySystemId = $arFields['PAY_SYSTEM_ID'];
// let DoCalculateOrder know we send location in CODEs
$arOptions = array('LOCATION_IN_CODES' => true, 'CART_FIX' => 'Y', 'CURRENCY' => $currencyId);
$arErrors = $arWarnings = array();
$invoiceCompatible = Compatible\Invoice::create($arFields);
$arOptions['ORDER'] = $invoiceCompatible->getOrder();
$arOrder = CSaleOrder::DoCalculateOrder(
$siteId, $saleUserId, $arShoppingCart, $personTypeId, $arOrderPropsValues,
$deliveryId, $paySystemId, $arOptions, $arErrors, $arWarnings
);
if (!is_array($arOrder) || empty($arOrder))
{
if (is_array($arErrors) && isset($arErrors[0]['TEXT']))
{
$this->LAST_ERROR = $arErrors[0]['TEXT'];
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
}
return false;
}
//
if ($bRecalculate)
{
foreach ($arOrder as $k => $v)
$arRecalculated[$k] = $v;
return true;
}
// merge order fields
$arAdditionalFields = array();
foreach ($arFields as $k => $v)
{
if ($k === 'PRODUCT_ROWS') continue;
$arAdditionalFields[$k] = $v;
}
// skip user fields
$userFields = $GLOBALS['USER_FIELD_MANAGER']->GetUserFields(self::$sUFEntityID);
if (is_array($userFields))
{
foreach(array_keys($userFields) as $fieldName)
{
if (array_key_exists($fieldName, $arAdditionalFields))
unset($arAdditionalFields[$fieldName]);
}
}
unset($userFields);
$arOrder['LOCATION_IN_CODES'] = true; // let DoSaveOrder know we send location in IDs
// saving order
$arErrors = array();
$arAdditionalFields['CUSTOM_DISCOUNT_PRICE'] = true;
$orderID = Compatible\Helper::doSaveOrder($arOrder, $arAdditionalFields, $tmpOrderId, $arErrors);
if(!(is_int($orderID) && $orderID > 0))
{
if (is_array($arErrors) && isset($arErrors[0]))
$this->LAST_ERROR = $arErrors[0];
else
$this->LAST_ERROR = GetMessage('CRM_INVOICE_ERR_UNK_ON_SAVE_ORDER');
$GLOBALS['APPLICATION']->ThrowException($this->LAST_ERROR);
}
// update user fields
if(is_int($orderID) && $orderID > 0)
{
CCrmEntityHelper::NormalizeUserFields($arFields, self::$sUFEntityID, $GLOBALS['USER_FIELD_MANAGER'], array('IS_NEW' => ($tmpOrderId === 0)));
$GLOBALS['USER_FIELD_MANAGER']->Update(self::$sUFEntityID, $orderID, $arFields);
}
if(is_int($orderID) && $orderID > 0 && isset($options['REGISTER_SONET_EVENT']) && $options['REGISTER_SONET_EVENT'] === true)
{
$prevResponsibleID = is_array($arPrevOrder) && isset($arPrevOrder['RESPONSIBLE_ID'])
? intval($arPrevOrder['RESPONSIBLE_ID']) : 0;
$responsibleID = isset($arFields['RESPONSIBLE_ID']) ? intval($arFields['RESPONSIBLE_ID']) : 0;
if($tmpOrderId <= 0)
{
if (!empty($orderStatus))
$arFields['STATUS_ID'] = $orderStatus;
self::RegisterLiveFeedEvent($arFields, $orderID, $userId);
unset($arFields['STATUS_ID']);
if ($responsibleID > 0 && Settings\Crm::isLiveFeedRecordsGenerationEnabled())
{
CCrmSonetSubscription::RegisterSubscription(
CCrmOwnerType::Invoice,
$orderID,
CCrmSonetSubscriptionType::Responsibility,
$responsibleID
);
}
}
else
{
$newDealID = isset($arFields['UF_DEAL_ID']) ? intval($arFields['UF_DEAL_ID']) : 0;
$oldDealID = isset($arPrevOrder['UF_DEAL_ID']) ? intval($arPrevOrder['UF_DEAL_ID']) : 0;
$newCompanyID = isset($arFields['UF_COMPANY_ID']) ? intval($arFields['UF_COMPANY_ID']) : 0;
$oldCompanyID = isset($arPrevOrder['UF_COMPANY_ID']) ? intval($arPrevOrder['UF_COMPANY_ID']) : 0;
$newContactID = isset($arFields['UF_CONTACT_ID']) ? intval($arFields['UF_CONTACT_ID']) : 0;
$oldContactID = isset($arPrevOrder['UF_CONTACT_ID']) ? intval($arPrevOrder['UF_CONTACT_ID']) : 0;
$parents = array();
$parentsChanged = $newDealID !== $oldDealID || $newCompanyID !== $oldCompanyID || $newContactID !== $oldContactID;
if($parentsChanged)
{
if($newDealID > 0)
{
$parents[] = array(
'ENTITY_TYPE_ID' => CCrmOwnerType::Deal,
'ENTITY_ID' => $newDealID
);
}
if($newCompanyID > 0)
{
$parents[] = array(
'ENTITY_TYPE_ID' => CCrmOwnerType::Company,
'ENTITY_ID' => $newCompanyID
);
}
if($newContactID > 0)
{
$parents[] = array(
'ENTITY_TYPE_ID' => CCrmOwnerType::Contact,
'ENTITY_ID' => $newContactID
);
}
}
$oldOrderStatus = isset($arPrevOrder['STATUS_ID']) ? $arPrevOrder['STATUS_ID'] : '';
self::SynchronizeLiveFeedEvent(
$orderID,
array(
'PROCESS_PARENTS' => $parentsChanged,
'PARENTS' => $parents,
'REFRESH_DATE' => $orderStatus !== $oldOrderStatus,
'START_RESPONSIBLE_ID' => $prevResponsibleID,
'FINAL_RESPONSIBLE_ID' => $responsibleID,
'TOPIC' => isset($arPrevOrder['ORDER_TOPIC']) ? $arPrevOrder['ORDER_TOPIC'] : $orderID
)
);
if (
$responsibleID !== $prevResponsibleID
&& Settings\Crm::isLiveFeedRecordsGenerationEnabled()
)
{
CCrmSonetSubscription::ReplaceSubscriptionByEntity(
CCrmOwnerType::Invoice,
$orderID,
CCrmSonetSubscriptionType::Responsibility,
$responsibleID,
$prevResponsibleID,
true
);
}
}
}
}
if (intval($orderID) > 0)
{
if (!empty($orderStatus) && !(isset($options['SKIP_STATUS']) && $options['SKIP_STATUS']))
{
// set status
$this->SetStatus($orderID, $orderStatus, false, array('SKIP_UPDATE' => true));
}
else if ($paidStateCanceled)
{
Compatible\Helper::payOrder($tmpOrderId, true);
}
$securityRegisterOptions = (new \Bitrix\Crm\Security\Controller\RegisterOptions())
->setEntityAttributes($arEntityAttr)
;
\Bitrix\Crm\Security\Manager::getEntityController(CCrmOwnerType::Invoice)
->register(self::$TYPE_NAME, $orderID, $securityRegisterOptions)
;
$newDealID = isset($arFields['UF_DEAL_ID']) ? (int)$arFields['UF_DEAL_ID'] : 0;
$oldDealID = is_array($arPrevOrder) && isset($arPrevOrder['UF_DEAL_ID']) ? (int)$arPrevOrder['UF_DEAL_ID'] : 0;
if($newDealID)
{
Bitrix\Crm\Statistics\DealInvoiceStatisticEntry::register($newDealID);
}
if($oldDealID > 0 && $oldDealID !== $newDealID)
{
Bitrix\Crm\Statistics\DealInvoiceStatisticEntry::register($oldDealID);
}
if(!isset($options['UPDATE_SEARCH']) || $options['UPDATE_SEARCH'] === true)
{
$arFilterTmp = Array('ID' => $orderID);
if (!$this->bCheckPermission)
$arFilterTmp["CHECK_PERMISSIONS"] = "N";
CCrmSearch::UpdateSearch($arFilterTmp, 'INVOICE', true);
}
}
if ($orderID > 0)
{
$isNew = $tmpOrderId <= 0;
if(defined('BX_COMP_MANAGED_CACHE'))
{
$GLOBALS['CACHE_MANAGER']->CleanDir('b_crm_invoice');
}
//Statistics & History -->
if((!isset($options['REGISTER_STATISTICS']) || $options['REGISTER_STATISTICS'] === true) && $arFields['IS_RECURRING'] !== 'Y')
{
Bitrix\Crm\History\InvoiceStatusHistoryEntry::register($orderID, null, array('IS_NEW' => $isNew));
Bitrix\Crm\Statistics\InvoiceSumStatisticEntry::register($orderID, null);
}
//<-- Statistics & History
//region Search content index
Bitrix\Crm\Search\SearchContentBuilderFactory::create(CCrmOwnerType::Invoice)->build($orderID);
//endregion Search content index
if (!isset($arFields['ID']))
$arFields['ID'] = $orderID;
if (!empty($orderStatus))
$arFields['STATUS_ID'] = $orderStatus;
foreach (GetModuleEvents('crm', (($tmpOrderId <= 0) ? 'OnAfterCrmInvoiceAdd' : 'OnAfterCrmInvoiceUpdate'), true) as $arEvent)
ExecuteModuleEventEx($arEvent, array(&$arFields));
}
return $orderID;
}