1
0
mirror of synced 2024-11-24 14:26:08 +03:00

ref #92774 Поддержка пользовательских полей (#323)

This commit is contained in:
Kocmonavtik 2023-12-19 17:13:31 +03:00 committed by GitHub
parent e918317f6a
commit 6d479ae441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 947 additions and 20 deletions

View File

@ -1,3 +1,6 @@
## 2023-12-18 v.6.5.0
- Добавлена поддержка функционала пользовательских полей
## 2023-12-13 v.6.4.13
- Исправлена ошибка с получением данных программы лояльности администратора при изменении заказа в админке

View File

@ -10,6 +10,8 @@ use Intaro\RetailCrm\Service\Utils;
use RetailCrm\Exception\CurlException;
use RetailCrm\Exception\InvalidJsonException;
use Intaro\RetailCrm\Service\ManagerService;
use Bitrix\Main\UserFieldTable;
use Bitrix\Main\UserFieldLangTable;
use Bitrix\Sale\Internals\SiteCurrencyTable;
IncludeModuleLangFile(__FILE__);
@ -438,6 +440,188 @@ class RCrmActions
return $result;
}
public static function customOrderPropList()
{
$typeMatched = [
'STRING' => 'STRING',
'NUMBER' => 'NUMERIC',
'Y/N' => 'BOOLEAN',
'DATE' => 'DATE'
];
//Базовые свойства заказа и используемые свойства в функционале модуля
$bannedCodeList = [
'FIO',
'EMAIL',
'PHONE',
'ZIP',
'CITY',
'LOCATION',
'ADDRESS',
'COMPANY',
'COMPANY_ADR',
'INN',
'KPP',
'CONTACT_PERSON',
'FAX',
'LP_BONUS_INFO',
'LP_DISCOUNT_INFO',
''
];
$listPersons = PersonType::getList([
'select' => ['ID', 'NAME'],
'filter' => ['ENTITY_REGISTRY_TYPE' => 'ORDER']
])->fetchAll();
$persons = [];
foreach ($listPersons as $person) {
$persons[$person['ID']] = $person['NAME'];
}
$propsList = OrderPropsTable::getList([
'select' => ['ID', 'CODE', 'NAME', 'PERSON_TYPE_ID', 'TYPE'],
'filter' => [
['!=CODE' => $bannedCodeList],
['?TYPE' => 'STRING | NUMBER | Y/N | DATE'],
['MULTIPLE' => 'N'],
['ACTIVE' => 'Y']
]
])->fetchAll();
$resultList = [];
foreach ($propsList as $prop) {
$type = $typeMatched[$prop['TYPE']] ?? $prop['TYPE'];
$key = $prop['ID'] . '#' . $prop['CODE'];
$resultList[$type . '_TYPE'][$key] = $prop['NAME'] . ' (' . $persons[$prop['PERSON_TYPE_ID']] . ')';
}
ksort($resultList);
return $resultList;
}
public static function customUserFieldList()
{
$typeMatched = [
'string' => 'STRING',
'double' => 'NUMERIC',
'boolean' => 'BOOLEAN',
'date' => 'DATE',
'integer' => 'INTEGER'
];
$userFields = UserFieldTable::getList([
'select' => ['ID', 'FIELD_NAME', 'USER_TYPE_ID'],
'filter' => [
['ENTITY_ID' => 'USER'],
['?FIELD_NAME' => '~%INTARO%'],
['!=FIELD_NAME' => 'UF_SUBSCRIBE_USER_EMAIL'],
['!=USER_TYPE_ID' => 'datetime'],
['?USER_TYPE_ID' => 'string | date | integer | double | boolean'],
['MULTIPLE' => 'N'],
]
])->fetchAll();
$resultList = [];
foreach ($userFields as $userField) {
$label = UserFieldLangTable::getList([
'select' => ['EDIT_FORM_LABEL'],
'filter' => [
["USER_FIELD_ID" => $userField['ID']],
['LANGUAGE_ID' => LANGUAGE_ID]
]
])->fetch();
$type = $typeMatched[$userField['USER_TYPE_ID']] ?? $userField['USER_TYPE_ID'];
$resultList[$type . '_TYPE'][$userField['FIELD_NAME']] = $label['EDIT_FORM_LABEL'];
}
ksort($resultList);
return $resultList;
}
public static function getTypeUserField()
{
$userFields = UserFieldTable::getList([
'select' => ['FIELD_NAME', 'USER_TYPE_ID'],
'filter' => [
['ENTITY_ID' => 'USER'],
['?FIELD_NAME' => '~%INTARO%'],
['!=FIELD_NAME' => 'UF_SUBSCRIBE_USER_EMAIL'],
['?USER_TYPE_ID' => 'string | date | datetime | integer | double | boolean'],
['MULTIPLE' => 'N'],
]
])->fetchAll();
$result = [];
foreach ($userFields as $userField) {
$result[$userField['FIELD_NAME']] = $userField['USER_TYPE_ID'];
}
return $result;
}
public static function convertCmsFieldToCrmValue($value, $type)
{
$result = $value;
switch ($type) {
case 'boolean':
$result = $value === '1' ? 1 : 0;
break;
case 'Y/N':
$result = $result === 'Y' ? 1 : 0;
break;
case 'STRING':
case 'string':
$result = strlen($value) <= 500 ? $value : '';
break;
case 'datetime':
$result = date('Y-m-d', strtotime($value));
break;
}
return $result;
}
public static function convertCrmValueToCmsField($crmValue, $type)
{
$result = $crmValue;
switch ($type) {
case 'Y/N':
case 'boolean':
$result = $crmValue == 1 ? 'Y' : 'N';
break;
case 'DATE':
case 'date':
if (empty($crmValue)) {
return '';
}
try {
$result = date('d.m.Y', strtotime($crmValue));
} catch (\Exception $exception) {
$result = '';
}
break;
case 'STRING':
case 'string':
case 'text':
$result = strlen($crmValue) <= 500 ? $crmValue : '';
break;
}
return $result;
}
public static function sendConfiguration($api, $active = true)
{
$scheme = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';

View File

@ -99,7 +99,7 @@ class RestNormalizer
$formatted[ $code ] = $this->formatting($value, true);
}
if (empty($formatted[$code])) {
if (empty($formatted[$code] && $formatted[$code] !== 0)) {
if ($this->clear === true) {
unset($formatted[ $code ]);
}

View File

@ -175,6 +175,7 @@ class RetailCrmEvent
'optionsContragentType' => $optionsContragentType,
'optionsSitesList' => $optionsSitesList,
'optionsCustomFields' => $optionsCustomFields,
'customOrderProps' => RetailcrmConfigProvider::getMatchedOrderProps(),
]);
//many sites?

View File

@ -49,6 +49,7 @@ class RetailCrmHistory
public static $CRM_CANSEL_ORDER = 'cansel_order';
public static $CRM_CURRENCY = 'currency';
public static $CRM_DISCOUNT_ROUND = 'discount_round';
public static $CUSTOM_FIELDS_IS_ACTIVE = 'N';
const PAGE_LIMIT = 25;
@ -63,6 +64,21 @@ class RetailCrmHistory
$historyStart = RetailcrmConfigProvider::getCustomersHistorySinceId();
$api = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
$matchedCustomFields = RetailcrmConfigProvider::getMatchedUserFields();
$matchedCustomFields = is_array($matchedCustomFields) ? array_flip($matchedCustomFields) : [];
if (method_exists(RCrmActions::class, 'getTypeUserField')
&& method_exists(RCrmActions::class, 'convertCrmValueToCmsField')
) {
self::$CUSTOM_FIELDS_IS_ACTIVE = RetailcrmConfigProvider::getCustomFieldsStatus();
}
$customUserFieldTypes = [];
if (self::$CUSTOM_FIELDS_IS_ACTIVE === 'Y') {
$customUserFieldTypes = RCrmActions::getTypeUserField();
}
if ($historyStart && $historyStart > 0) {
$historyFilter['sinceId'] = $historyStart;
}
@ -124,6 +140,8 @@ class RetailCrmHistory
$customerBuilder->setDataCrm($customer)->build();
$customFields = self::getCustomUserFields($customer, $matchedCustomFields, $customUserFieldTypes);
if (!isset($customer['externalId'])) {
if (!isset($customer['id'])) {
continue;
@ -155,7 +173,7 @@ class RetailCrmHistory
if ($registerNewUser === true) {
$customerBuilder->buildPassword();
$registeredUserID = $newUser->Add(self::getDataUser($customerBuilder));
$registeredUserID = $newUser->Add(self::getDataUser($customerBuilder, $customFields));
if ($registeredUserID === false) {
RCrmActions::eventLog(
@ -197,9 +215,11 @@ class RetailCrmHistory
}
$customerArray = $customerBuilder->getCustomer()->getObjectToArray();
$u = $newUser->Update($customer['externalId'], self::convertBooleanFields($customerArray));
$customerArray = array_merge($customerArray, $customFields);
if (!$u) {
$queryUpdate = $newUser->Update($customer['externalId'], self::convertBooleanFields($customerArray));
if (!$queryUpdate) {
RCrmActions::eventLog(
'RetailCrmHistory::customerHistory',
'Error update user',
@ -261,6 +281,24 @@ class RetailCrmHistory
$contragentTypes = array_flip(RetailcrmConfigProvider::getContragentTypes());
$shipmentDeducted = RetailcrmConfigProvider::getShipmentDeducted();
$matchedCustomUserFields = RetailcrmConfigProvider::getMatchedUserFields() ?? [];
$matchedCustomUserFields = is_array($matchedCustomUserFields) ? array_flip($matchedCustomUserFields) : [];
$matchedCustomOrderFields = RetailcrmConfigProvider::getMatchedOrderProps() ?? [];
$matchedCustomOrderFields = is_array($matchedCustomOrderFields) ? array_flip($matchedCustomOrderFields) : [];
if (method_exists(RCrmActions::class, 'getTypeUserField')
&& method_exists(RCrmActions::class, 'convertCrmValueToCmsField')
) {
self::$CUSTOM_FIELDS_IS_ACTIVE = RetailcrmConfigProvider::getCustomFieldsStatus();
}
$customUserFieldTypes = [];
if (self::$CUSTOM_FIELDS_IS_ACTIVE === 'Y') {
$customUserFieldTypes = RCrmActions::getTypeUserField();
}
$api = new RetailCrm\ApiClient(RetailcrmConfigProvider::getApiUrl(), RetailcrmConfigProvider::getApiKey());
$page = 1;
/* @var OrderLoyaltyDataService $orderLoyaltyDataService */
@ -459,6 +497,9 @@ class RetailCrmHistory
$newUser = new CUser();
$customerArray = $corporateCustomerBuilder->getCustomer()->getObjectToArray();
$customFields = self::getCustomUserFields($userData, $matchedCustomUserFields, $customUserFieldTypes);
$customerArray = array_merge($customerArray, $customFields);
if (!array_key_exists('UF_SUBSCRIBE_USER_EMAIL', $customerArray)) {
$customerArray['UF_SUBSCRIBE_USER_EMAIL'] = 'Y';
}
@ -925,7 +966,8 @@ class RetailCrmHistory
}
if ($registerNewUser === true) {
$registeredUserID = $newUser->Add(self::getDataUser($customerBuilder));
$customFields = self::getCustomUserFields($response['customer'], $matchedCustomUserFields, $customUserFieldTypes);
$registeredUserID = $newUser->Add(self::getDataUser($customerBuilder, $customFields));
if ($registeredUserID === false) {
RCrmActions::eventLog(
@ -1216,6 +1258,26 @@ class RetailCrmHistory
}
$newOrder->setField('PRICE', $orderSumm);
if (self::$CUSTOM_FIELDS_IS_ACTIVE === 'Y' && !empty($matchedCustomOrderFields)) {
foreach ($order['customFields'] as $code => $value) {
if (isset($matchedCustomOrderFields[$code])) {
$arrayIdentifier = explode('#', $matchedCustomOrderFields[$code], 2);
$property = $propertyCollection->getItemByOrderPropertyId($arrayIdentifier[0]);
$value = RCrmActions::convertCrmValueToCmsField($value, $property->getType());
$queryResult = $property->setField('VALUE', $value);
if (!$queryResult->isSuccess()) {
RCrmActions::eventLog(
'RetailCrmHistory::orderHistory',
'CustomOrderPropSave',
'Error when saving a property: ' . $arrayIdentifier[1]
);
}
}
}
}
self::orderSave($newOrder);
if ($optionsOrderNumbers === 'Y' && isset($order['number'])) {
@ -2113,7 +2175,7 @@ class RetailCrmHistory
* @param $customerBuilder
* @return array
*/
private static function getDataUser($customerBuilder)
private static function getDataUser($customerBuilder, $customFields)
{
$customerArray = $customerBuilder->getCustomer()->getObjectToArray();
@ -2121,6 +2183,27 @@ class RetailCrmHistory
$customerArray['UF_SUBSCRIBE_USER_EMAIL'] = 'Y';
}
$customerArray = array_merge($customerArray, $customFields);
return self::convertBooleanFields($customerArray);
}
private static function getCustomUserFields($customer, $matchedCustomFields, $customUserFieldTypes)
{
$customFields = [];
if (self::$CUSTOM_FIELDS_IS_ACTIVE === 'Y'
&& isset($customer['customFields'])
&& is_array($customer['customFields'])
) {
foreach ($customer['customFields'] as $code => $value) {
if (isset($matchedCustomFields[$code]) && !empty($customUserFieldTypes[$matchedCustomFields[$code]])) {
$type = $customUserFieldTypes[$matchedCustomFields[$code]];
$customFields[$matchedCustomFields[$code]] = RCrmActions::convertCrmValueToCmsField($value, $type);
}
}
}
return $customFields;
}
}

View File

@ -123,6 +123,11 @@ class RetailCrmOrder
$countryList = BitrixOrderService::getCountryList();
$deliveryAddress = ['city' => '', 'text' => '', 'index' => '', 'region' => '', 'countryIso' => ''];
$isSendCustomFields = 'N';
if (method_exists(RCrmActions::class, 'convertCmsFieldToCrmValue')) {
$isSendCustomFields = RetailcrmConfigProvider::getCustomFieldsStatus();
}
//Order fields
foreach ($arOrder['PROPS']['properties'] as $prop) {
@ -131,10 +136,11 @@ class RetailCrmOrder
&& $search = array_search($prop['CODE'], $arParams['optionsLegalDetails'][$arOrder['PERSON_TYPE_ID']])
) {
$order['contragent'][$search] = $prop['VALUE'][0];//legal order data
} elseif (!empty($arParams['optionsCustomFields'])
&& $search = array_search($prop['CODE'], $arParams['optionsCustomFields'][$arOrder['PERSON_TYPE_ID']])
} elseif ($isSendCustomFields === 'Y'
&& !empty($arParams['customOrderProps'])
&& isset($arParams['customOrderProps'][$prop['ID'] . '#' . $prop['CODE']])
) {
$order['customFields'][$search] = $prop['VALUE'][0];//custom properties
$order['customFields'][$arParams['customOrderProps'][$prop['ID'] . '#' . $prop['CODE']]] = RCrmActions::convertCmsFieldToCrmValue($prop['VALUE'][0], $prop['TYPE']);
} elseif (is_array($arParams['optionsOrderProps'][$arOrder['PERSON_TYPE_ID']])
&& $search = array_search($prop['CODE'], $arParams['optionsOrderProps'][$arOrder['PERSON_TYPE_ID']])) {//other
if (in_array($search, ['fio', 'phone', 'email'])) {//fio, phone, email
@ -557,6 +563,7 @@ class RetailCrmOrder
'optionsContragentType' => $optionsContragentType,
'optionsSitesList' => RetailcrmConfigProvider::getSitesList(),
'optionsCustomFields' => $optionsCustomFields,
'customOrderProps' => RetailcrmConfigProvider::getMatchedOrderProps(),
];
$recOrders = [];

View File

@ -29,6 +29,10 @@ class RetailCrmUser
$customer['createdAt'] = new \DateTime($arFields['DATE_REGISTER']);
$customer['contragent'] = ['contragentType' => $contragentType];
if (RetailcrmConfigProvider::getCustomFieldsStatus() === 'Y') {
$customer['customFields'] = self::getCustomFields($arFields);
}
if ($send && isset($_COOKIE['_rc']) && $_COOKIE['_rc'] != '') {
$customer['browserId'] = $_COOKIE['_rc'];
}
@ -75,6 +79,10 @@ class RetailCrmUser
$customer = self::getSimpleCustomer($arFields);
$found = false;
if (RetailcrmConfigProvider::getCustomFieldsStatus() === 'Y') {
$customer['customFields'] = self::getCustomFields($arFields);
}
if (count($optionsSitesList) > 0) {
foreach ($optionsSitesList as $site) {
$userCrm = RCrmActions::apiMethod($api, 'customersGet', __METHOD__, $arFields['ID'], $site);
@ -151,4 +159,26 @@ class RetailCrmUser
return $customer;
}
private static function getCustomFields(array $arFields)
{
if (!method_exists(RCrmActions::class, 'getTypeUserField')
|| !method_exists(RCrmActions::class, 'convertCmsFieldToCrmValue')
) {
return [];
}
$customUserFields = RetailcrmConfigProvider::getMatchedUserFields();
$typeList = RCrmActions::getTypeUserField();
$result = [];
foreach ($customUserFields as $code => $codeCrm) {
if (isset($arFields[$code])) {
$type = $typeList[$code] ?? '';
$result[$codeCrm] = RCrmActions::convertCmsFieldToCrmValue($arFields[$code], $type);
}
}
return $result;
}
}

View File

@ -1 +1 @@
- Исправлена ошибка с получением данных программы лояльности администратора при изменении заказа в админке
- Добавлена поддержка функционала пользовательских полей

View File

@ -1,6 +1,6 @@
<?php
$arModuleVersion = [
'VERSION' => '6.4.13',
'VERSION_DATE' => '2023-12-13 17:00:00'
'VERSION' => '6.5.0',
'VERSION_DATE' => '2023-12-18 13:00:00'
];

View File

@ -117,3 +117,18 @@ $MESS ['WRONG_CREDENTIALS'] = 'Enter the address and authorization key of the CR
$MESS ['Wrong "apiKey" value.'] = 'Invalid authorization key';
$MESS ['ORDER_TRACK_NUMBER'] = 'Receive track number';
$MESS ['CUSTOM_FIELDS_TITLE'] = 'User fields';
$MESS ['CUSTOM_FIELDS_CAPTION'] = 'Matching user fields';
$MESS ['CUSTOM_FIELDS_TOGGLE_MSG'] = 'Activate synchronization of user fields';
$MESS ['CUSTOM_FIELDS_ORDER_LABEL'] = 'Custom order fields';
$MESS ['CUSTOM_FIELDS_USER_LABEL'] = 'User custom fields';
$MESS ['INTEGER_TYPE'] = 'An integer';
$MESS ['STRING_TYPE'] = 'Line/Text';
$MESS ['NUMERIC_TYPE'] = 'Number';
$MESS ['BOOLEAN_TYPE'] = 'Check box (yes/no)';
$MESS ['DATE_TYPE'] = 'Date';
$MESS ['NOTATION_CUSTOM_FIELDS'] = 'Before enabling this functionality, make sure that you do not have customized files for working with orders and customers associated with older versions of the module.';
$MESS ['NOTATION_MATCHED_CUSTOM_FIELDS'] = 'For correct data exchange, the types of matched fields must be the same!';
$MESS ['ADD_LABEL'] = 'Add';
$MESS ['DELETE_MATCHED'] = 'Delete';

View File

@ -176,3 +176,18 @@ $MESS ['WRONG_CREDENTIALS'] = 'Введите адрес и ключ автор
$MESS ['Wrong "apiKey" value.'] = 'Недействительный ключ авторизации';
$MESS ['ORDER_TRACK_NUMBER'] = 'Получать трек-номер';
$MESS ['CUSTOM_FIELDS_TITLE'] = 'Пользовательские поля';
$MESS ['CUSTOM_FIELDS_CAPTION'] = 'Сопоставление пользовательских полей';
$MESS ['CUSTOM_FIELDS_TOGGLE_MSG'] = 'Активировать синхронизацию пользовательских полей';
$MESS ['CUSTOM_FIELDS_ORDER_LABEL'] = 'Пользовательские поля заказа';
$MESS ['CUSTOM_FIELDS_USER_LABEL'] = 'Пользовательские поля клиента';
$MESS ['INTEGER_TYPE'] = 'Целое число';
$MESS ['STRING_TYPE'] = 'Строка/Текст';
$MESS ['NUMERIC_TYPE'] = 'Число';
$MESS ['BOOLEAN_TYPE'] = 'Флажок (да/нет)';
$MESS ['DATE_TYPE'] = 'Дата';
$MESS ['NOTATION_CUSTOM_FIELDS'] = 'Перед подключением данного функционала, убедитесь, что у вас нет кастомизированных файлов по работе с заказами и клиентами, связанных со старыми версиями модуля.';
$MESS ['NOTATION_MATCHED_CUSTOM_FIELDS'] = 'Для корректного обмена данными типы сопоставляемых полей должны быть одинаковыми!';
$MESS ['ADD_LABEL'] = 'Добавить';
$MESS ['DELETE_MATCHED'] = 'Удалить';

View File

@ -117,6 +117,12 @@ class ConfigProvider
/** @var bool|null|string $loyaltyProgramStatus */
protected static $loyaltyProgramStatus;
/** @var array $mathedCustomProps */
protected static $mathedCustomProps;
/** @var array $mathedCustomFields */
protected static $mathedCustomFields;
/**
* @return bool|string|null
*/
@ -1169,4 +1175,69 @@ class ConfigProvider
{
static::setOption(Constants::RECEIVE_TRACK_NUMBER_DELIVERY, $trackNumberStatus);
}
/**
* @return string|null
*/
public static function getCustomFieldsStatus()
{
return static::getOption(Constants::CUSTOM_FIELDS_TOGGLE);
}
/**
* @param bool|string|null $customFieldsStatus
* @return void
* @throws \Bitrix\Main\ArgumentOutOfRangeException
*/
public static function setCustomFieldsStatus($customFieldsStatus)
{
static::setOption(Constants::CUSTOM_FIELDS_TOGGLE, $customFieldsStatus);
}
/**
* @return array
*/
public static function getMatchedOrderProps()
{
if (self::isEmptyNotZero(static::$mathedCustomProps)) {
static::$mathedCustomProps = static::getUnserializedOption(Constants::MATCHED_CUSTOM_PROPS);
}
return static::$mathedCustomProps;
}
/**
* @param array|null $customPropsList
*
* @return void
* @throws \Bitrix\Main\ArgumentOutOfRangeException
*/
public static function setMatchedOrderProps(?array $customPropsList)
{
static::setOption(Constants::MATCHED_CUSTOM_PROPS, serialize($customPropsList));
'selected';
}
/**
* @return array
*/
public static function getMatchedUserFields()
{
if (self::isEmptyNotZero(static::$mathedCustomFields)) {
static::$mathedCustomFields = static::getUnserializedOption(Constants::MATCHED_CUSTOM_USER_FIELDS);
}
return static::$mathedCustomFields;
}
/**
* @param array|null $customUserFields
*
* @return void
* @throws \Bitrix\Main\ArgumentOutOfRangeException
*/
public static function setMatchedUserFields(?array $customUserFields)
{
static::setOption(Constants::MATCHED_CUSTOM_USER_FIELDS, serialize($customUserFields));
}
}

View File

@ -105,4 +105,7 @@ class Constants
public const SITES_AVAILABLE = 'sites_available';
public const RECEIVE_TRACK_NUMBER_DELIVERY = 'receive_track_number_delivery';
public const CUSTOM_FIELDS_TOGGLE = 'custom_fields_toggle';
public const MATCHED_CUSTOM_PROPS = 'matched_order_props';
public const MATCHED_CUSTOM_USER_FIELDS = 'matched_custom_field';
}

View File

@ -120,6 +120,16 @@ if (file_exists($_SERVER["DOCUMENT_ROOT"] . '/bitrix/modules/intaro.retailcrm/cl
$arResult['arSites'] = RCrmActions::getSitesList();
$arResult['arCurrencySites'] = RCrmActions::getCurrencySites();
$arResult['bitrixOrdersCustomProp'] = [];
$arResult['bitrixCustomUserFields'] = [];
if (method_exists(RCrmActions::class, 'customOrderPropList')
&& method_exists(RCrmActions::class, 'customUserFieldList')
) {
$arResult['bitrixOrdersCustomProp'] = RCrmActions::customOrderPropList();
$arResult['bitrixCustomUserFields'] = RCrmActions::customUserFieldList();
}
//ajax update deliveryServices
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') && isset($_POST['ajax']) && ($_POST['ajax'] === 1)) {
$api_host = COption::GetOptionString($mid, $CRM_API_HOST_OPTION, 0);
@ -934,6 +944,34 @@ if (isset($_POST['Update']) && ($_POST['Update'] === 'Y')) {
$bitrixCorpAdres
);
if (isset($_POST['custom_fields_toggle']) && $_POST['custom_fields_toggle'] === 'on') {
$counter = 1;
$customOrderProps = [];
$customUserFields = [];
foreach ($arResult['bitrixOrdersCustomProp'] as $list) {
foreach ($list as $code => $text) {
if (!empty($_POST['bitrixOrderFields_' . $code]) && !empty($_POST['crmOrderFields_' . $code])) {
$customOrderProps[htmlspecialchars($_POST['bitrixOrderFields_' . $code])] = htmlspecialchars($_POST['crmOrderFields_' . $code]);
}
}
}
foreach ($arResult['bitrixCustomUserFields'] as $list) {
foreach ($list as $code => $text) {
if (!empty($_POST['bitrixUserFields_' . $code]) && !empty($_POST['crmUserFields_' . $code])) {
$customUserFields[htmlspecialchars($_POST['bitrixUserFields_' . $code])] = htmlspecialchars($_POST['crmUserFields_' . $code]);
}
}
}
ConfigProvider::setCustomFieldsStatus('Y');
ConfigProvider::setMatchedOrderProps($customOrderProps);
ConfigProvider::setMatchedUserFields($customUserFields);
} else {
ConfigProvider::setCustomFieldsStatus('N');
}
$request = Application::getInstance()->getContext()->getRequest();
if ($request->isHttps() === true) {
@ -961,6 +999,16 @@ if (isset($_POST['Update']) && ($_POST['Update'] === 'Y')) {
$arResult['sitesList'] = $APPLICATION->ConvertCharsetArray($api->sitesList()->sites, 'utf-8', SITE_CHARSET);
$arResult['inventoriesList'] = $APPLICATION->ConvertCharsetArray($api->storesList()->stores, 'utf-8', SITE_CHARSET);
$arResult['priceTypeList'] = $APPLICATION->ConvertCharsetArray($api->pricesTypes()->priceTypes, 'utf-8', SITE_CHARSET);
$arResult['crmCustomOrderFields'] = $APPLICATION->ConvertCharsetArray(
$api->customFieldsList(['entity' => 'order', 'type' => ['string','text', 'numeric', 'boolean', 'date']], 250)->customFields,
'utf-8',
SITE_CHARSET
);
$arResult['crmCustomUserFields'] = $APPLICATION->ConvertCharsetArray(
$api->customFieldsList(['entity' => 'customer', 'type' => ['string', 'text', 'integer', 'numeric', 'boolean', 'date']], 250)->customFields,
'utf-8',
SITE_CHARSET
);
} catch (\RetailCrm\Exception\CurlException $e) {
RCrmActions::eventLog(
'intaro.retailcrm/options.php', 'RetailCrm\ApiClient::*List::CurlException',
@ -976,6 +1024,40 @@ if (isset($_POST['Update']) && ($_POST['Update'] === 'Y')) {
echo CAdminMessage::ShowMessage(GetMessage('ERR_JSON'));
}
$crmCustomOrderFieldsList = [];
$crmCustomUserFieldsList = [];
foreach ($arResult['crmCustomOrderFields'] as $customField) {
$type = $customField['type'];
if ($type === 'text') {
$type = 'string';
}
$crmCustomOrderFieldsList[strtoupper($type) . '_TYPE'][] = ['name' => $customField['name'], 'code' => $customField['code']];
}
foreach ($arResult['crmCustomUserFields'] as $customField) {
$type = $customField['type'];
if ($type === 'text') {
$type = 'string';
}
$crmCustomUserFieldsList[strtoupper($type). '_TYPE'][] = ['name' => $customField['name'], 'code' => $customField['code']];
}
ksort($crmCustomOrderFieldsList);
ksort($crmCustomUserFieldsList);
$arResult['crmCustomOrderFields'] = $crmCustomOrderFieldsList;
$arResult['crmCustomUserFields'] = $crmCustomUserFieldsList;
unset($crmCustomOrderFieldsList, $crmCustomUserFieldsList);
$arResult['matchedOrderProps'] = ConfigProvider::getMatchedOrderProps();
$arResult['matchedUserFields'] = ConfigProvider::getMatchedUserFields();
$arResult['paymentTypesList'] = RetailCrmService::getAvailableTypes(
$availableSites,
$api->paymentTypesList()->paymentTypes
@ -1166,13 +1248,19 @@ if (isset($_POST['Update']) && ($_POST['Update'] === 'Y')) {
"TITLE" => GetMessage('ICRM_OPTIONS_ORDER_DISCHARGE_CAPTION'),
],
[
"DIV" => "edit5",
"DIV" => "edit5",
"TAB" => GetMessage('CUSTOM_FIELDS_TITLE'),
"ICON" => '',
"TITLE" => GetMessage('CUSTOM_FIELDS_CAPTION'),
],
[
"DIV" => "edit6",
"TAB" => GetMessage('UPLOAD_ORDERS_OPTIONS'),
"ICON" => '',
"TITLE" => GetMessage('ORDER_UPLOAD'),
],
[
"DIV" => "edit6",
"DIV" => "edit7",
"TAB" => GetMessage('OTHER_OPTIONS'),
"ICON" => '',
"TITLE" => GetMessage('ICRM_OPTIONS_ORDER_DISCHARGE_CAPTION'),
@ -1323,6 +1411,97 @@ if (isset($_POST['Update']) && ($_POST['Update'] === 'Y')) {
$('#loyalty_main_settings').toggle(500);
}
function switchCustomFieldsStatus() {
$('#custom_fields_settings').toggle(500);
}
function createMatched(type)
{
let bitrixName = "bitrix" + type + "Fields";
let crmName = "crm" + type + "Fields";
let elements = document.getElementsByClassName("adm-list-table-row matched-" + type);
let nextId = 1;
if (elements.length >= 1) {
let lastElement = elements[elements.length - 1];
nextId = parseInt(lastElement.id.replace("matched" + type + "Fields_", "")) + 1;
}
let matchedBlank = document.getElementById(type + "MatchedFieldsBlank");
let matchedElement = matchedBlank.cloneNode(true);
matchedElement.classList.add("adm-list-table-row");
matchedElement.classList.add("matched-" + type);
matchedElement.setAttribute("id", "matched" + type + "Fields_" + nextId);
matchedElement.querySelector(`select[name=${bitrixName}`).setAttribute("name", bitrixName + "_" + nextId);
matchedElement.querySelector(`select[name=${crmName}`).setAttribute("name", crmName + "_" + nextId);
matchedElement.removeAttribute("hidden");
document.getElementById(type + "_matched").appendChild(matchedElement);
}
function deleteMatched(element)
{
element.parentNode.parentNode.remove();
}
function generateEmptyMatched()
{
let elements = document.getElementsByClassName("adm-list-table-row matched-Order");
if (elements.length < 1) {
createMatched("Order");
}
elements = document.getElementsByClassName("adm-list-table-row matched-User");
if (elements.length < 1) {
createMatched("User");
}
}
function changeSelectBitrixValue(element, nameBitrix, nameCrm)
{
let name = element.getAttribute("name");
let uniqIdSelect = name.replace(nameBitrix, "");
let selectedValue = element.value;
let checkElements = document.getElementsByName(nameCrm + selectedValue);
if (checkElements.length === 0) {
let selectCrm = document.getElementsByName(nameCrm + uniqIdSelect);
selectCrm[0].setAttribute('name', nameCrm + selectedValue);
element.setAttribute('name', nameBitrix + selectedValue);
} else {
let text = element.options[element.selectedIndex].text;
element.value = uniqIdSelect;
alert('Поле: "' + text +'" уже используется в обмене');
}
}
function changeSelectCrmValue(element, nameElement)
{
let selectedValue = element.value;
let checkElement = document.getElementById(nameElement + selectedValue)
if (checkElement === null) {
element.id = nameElement + selectedValue;
} else {
let currentId = element.id;
let code = '';
if (currentId !== null) {
code = currentId.replace(nameElement, "");
}
let text = element.options[element.selectedIndex].text;
element.value = code;
alert('Поле: "' + text + '" уже используется в обмене');
}
}
$(document).ready(function() {
$('input.addr').change(function() {
splitName = $(this).attr('name').split('-');
@ -1877,7 +2056,6 @@ if (isset($_POST['Update']) && ($_POST['Update'] === 'Y')) {
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
<?php $tabControl->BeginNextTab(); ?>
<?php
//loyalty program options
@ -2072,6 +2250,274 @@ if (isset($_POST['Update']) && ($_POST['Update'] === 'Y')) {
</td>
</tr>
<?php $tabControl->BeginNextTab(); ?>
<?php
$customFieldsToggle = ConfigProvider::getCustomFieldsStatus();
?>
<tr class="">
<td class="option-head" colspan="2">
<p><b><?php echo GetMessage('NOTATION_CUSTOM_FIELDS'); ?></b></p>
<p><b><?php echo GetMessage('NOTATION_MATCHED_CUSTOM_FIELDS'); ?></b></p>
</td>
</tr>
<tr class="heading">
<td colspan="2" class="option-other-heading">
<b>
<label>
<input class="addr" type="checkbox" id="custom_fields_toggle" name="custom_fields_toggle" onclick="switchCustomFieldsStatus();" <?php if ($customFieldsToggle === 'Y') {
echo "checked";
} ?>>
<?php echo GetMessage('CUSTOM_FIELDS_TOGGLE_MSG'); ?>
</label>
</b>
</td>
</tr>
<tr>
<td>
<div id="custom_fields_settings" <?php if ($customFieldsToggle !== 'Y') {
echo "hidden";
} ?>>
<br>
<table class="adm-list-table">
<thead>
<tr class="adm-list-table-header">
<th class="adm-list-table-cell option-head option-other-top option-other-bottom" colspan="4">
<?php echo GetMessage('CUSTOM_FIELDS_ORDER_LABEL');?>
</th>
</tr>
</thead>
<tfoot>
<tr>
<th class="option-head option-other-top option-other-bottom" colspan="4">
<button class="adm-btn-save" type="button" onclick="createMatched(`Order`)"><?php echo GetMessage('ADD_LABEL'); ?></button>
</th>
</tr>
</tfoot>
<tbody id="Order_matched">
<?php
$matchedPropsNum = 1;
foreach ($arResult['matchedOrderProps'] as $bitrixProp => $crmField) {?>
<tr class="adm-list-table-row matched-Order" id="matchedOrderFields_<?php echo $matchedPropsNum ?>">
<td class="adm-list-table-cell adm-detail-content-cell-l" colspan="2" width="50%">
<select
style="width: 200px;" class="typeselect"
name="bitrixOrderFields_<?php echo $bitrixProp ?>"
onchange="changeSelectBitrixValue(this, 'bitrixOrderFields_', 'crmOrderFields_');"
>
<option value=""></option>
<?php foreach ($arResult['bitrixOrdersCustomProp'] as $type => $mass) {?>
<optgroup label="<?php echo GetMessage($type); ?>">
<?php foreach ($mass as $code => $prop) {?>
<option
value="<?php echo $code ?>"
<?php if ($bitrixProp === $code) echo 'selected'; ?>
>
<?php echo $prop ?>
</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
</td>
<td class="adm-list-table-cell adm-detail-content-cell-r" colspan="2" width="50%">
&nbsp;&nbsp;&nbsp;&nbsp;
<select
style="width: 200px;" class="typeselect"
name="crmOrderFields_<?php echo $bitrixProp ?>"
id="crmOrder_<?php echo $crmField?>"
onchange="changeSelectCrmValue(this, 'crmOrder_')"
>
<option value=""></option>
<?php foreach ($arResult['crmCustomOrderFields'] as $type => $mass) {?>
<optgroup label="<?php echo GetMessage($type); ?>">
<?php foreach ($mass as $crmProp) {?>
<option
value="<?php echo $crmProp['code'] ?>"
<?php if ($crmField === $crmProp['code']) echo 'selected'; ?>
>
<?php echo $crmProp['name'] ?>
</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
&nbsp;
<a onclick="deleteMatched(this)" style="cursor: pointer"><?php echo GetMessage('DELETE_MATCHED'); ?></a>
</td>
</tr>
<?php $matchedPropsNum++; }?>
</tbody>
</table>
<br>
<table class="adm-list-table">
<thead>
<tr class="adm-list-table-header">
<th class="adm-list-table-cell option-head option-other-top option-other-bottom" colspan="4">
<?php echo GetMessage('CUSTOM_FIELDS_USER_LABEL');?>
</th>
</tr>
</thead>
<tfoot>
<tr>
<th class="option-head option-other-top option-other-bottom" colspan="4">
<button class="adm-btn-save" type="button" onclick="createMatched(`User`)"><?php echo GetMessage('ADD_LABEL'); ?></button>
</th>
</tr>
</tfoot>
<tbody id="User_matched">
<?php
$matchedFieldsNum = 1;
foreach ($arResult['matchedUserFields'] as $bitrixProp => $crmField) {?>
<tr class="adm-list-table-row matched-User" id="matchedUserFields_<?php echo $matchedFieldsNum ?>">
<td class="adm-list-table-cell adm-detail-content-cell-l" colspan="2" width="50%">
<select
style="width: 200px;" class="typeselect"
name="bitrixUserFields_<?php echo $bitrixProp ?>"
onchange="changeSelectBitrixValue(this, 'bitrixUserFields_', 'crmUserFields_');"
>
<option value=""></option>
<?php foreach ($arResult['bitrixCustomUserFields'] as $type => $mass) {?>
<optgroup label="<?php echo GetMessage($type); ?>">
<?php foreach ($mass as $code => $prop) {?>
<option
value="<?php echo $code ?>"
<?php if ($bitrixProp === $code) echo 'selected'; ?>
>
<?php echo $prop ?>
</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
</td>
<td class="adm-list-table-cell adm-detail-content-cell-r" colspan="2" width="50%">
&nbsp;&nbsp;&nbsp;&nbsp;
<select
style="width: 200px;" class="typeselect"
name="crmUserFields_<?php echo $bitrixProp ?>"
id="crmClient_<?php echo $crmField?>"
onchange="changeSelectCrmValue(this, 'crmClient_')"
>
<option value=""></option>
<?php foreach ($arResult['crmCustomUserFields'] as $type => $mass) {?>
<optgroup label="<?php echo GetMessage($type); ?>">
<?php foreach ($mass as $crmProp) {?>
<option
value="<?php echo $crmProp['code'] ?>"
<?php if ($crmField === $crmProp['code']) echo 'selected'; ?>
>
<?php echo $crmProp['name'] ?>
</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
&nbsp;
<a onclick="deleteMatched(this)" style="cursor: pointer"><?php echo GetMessage('DELETE_MATCHED'); ?></a>
</td>
</tr>
<?php $matchedFieldsNum++; }?>
</tbody>
</table>
</div>
</td>
</tr>
<tr id="OrderMatchedFieldsBlank" hidden="hidden">
<td class="adm-list-table-cell adm-detail-content-cell-l" colspan="2" width="50%">
<select
style="width: 200px;" class="typeselect"
name="bitrixOrderFields"
onchange="changeSelectBitrixValue(this, 'bitrixOrderFields_', 'crmOrderFields_');"
>
<option value=""></option>
<?php foreach ($arResult['bitrixOrdersCustomProp'] as $type => $mass) {?>
<optgroup label="<?php echo GetMessage($type); ?>">
<?php foreach ($mass as $code => $prop) {?>
<option
value="<?php echo $code ?>"
<?php if ($bitrixProp === $code) echo 'selected'; ?>
>
<?php echo $prop ?>
</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
</td>
<td class="adm-list-table-cell adm-detail-content-cell-r" colspan="2" width="50%">
&nbsp;&nbsp;&nbsp;&nbsp;
<select
style="width: 200px;" class="typeselect"
name="crmOrderFields"
onchange="changeSelectCrmValue(this, 'crmOrder_')"
>
<option value=""></option>
<?php foreach ($arResult['crmCustomOrderFields'] as $type => $mass) {?>
<optgroup label="<?php echo GetMessage($type); ?>">
<?php foreach ($mass as $crmProp) {?>
<option
value="<?php echo $crmProp['code'] ?>"
<?php if ($crmField === $crmProp['code']) echo 'selected'; ?>
>
<?php echo $crmProp['name'] ?>
</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
&nbsp;
<a onclick="deleteMatched(this)" style="cursor: pointer"><?php echo GetMessage('DELETE_MATCHED'); ?></a>
</td>
</tr>
<tr id="UserMatchedFieldsBlank" hidden="hidden">
<td class="adm-list-table-cell adm-detail-content-cell-l" colspan="2" width="50%">
<select
style="width: 200px;" class="typeselect"
name="bitrixUserFields"
onchange="changeSelectBitrixValue(this, 'bitrixUserFields_', 'crmUserFields_');"
>
<option value=""></option>
<?php foreach ($arResult['bitrixCustomUserFields'] as $type => $mass) {?>
<optgroup label="<?php echo GetMessage($type); ?>">
<?php foreach ($mass as $code => $prop) {?>
<option value="<?php echo $code ?>">
<?php echo $prop ?>
</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
</td>
<td class="adm-list-table-cell adm-detail-content-cell-r" colspan="2" width="50%">
&nbsp;&nbsp;&nbsp;&nbsp;
<select
style="width: 200px;" class="typeselect"
name="crmUserFields"
onchange="changeSelectCrmValue(this, 'crmClient_')"
>
<option value=""></option>
<?php foreach ($arResult['crmCustomUserFields'] as $type => $mass) {?>
<optgroup label="<?php echo GetMessage($type); ?>">
<?php foreach ($mass as $crmProp) {?>
<option value="<?php echo $crmProp['code'] ?>">
<?php echo $crmProp['name'] ?>
</option>
<?php } ?>
</optgroup>
<?php } ?>
</select>
&nbsp;
<a onclick="deleteMatched(this)" style="cursor: pointer"><?php echo GetMessage('DELETE_MATCHED'); ?></a>
</td>
</tr>
<?php // Manual orders upload. ?>
<?php $tabControl->BeginNextTab(); ?>
<style type="text/css">
@ -2149,6 +2595,8 @@ if (isset($_POST['Update']) && ($_POST['Update'] === 'Y')) {
<script type="text/javascript">
$(document).ready(function() {
generateEmptyMatched();
$('#percent').width($('.install-progress-bar-outer').width());
$(window).resize(function() { // strechin progress bar

View File

@ -1195,7 +1195,14 @@ function update()
(new UpdateSubscribe())
->CopyFiles()
->addEvent()
->addCustomUserField();
->addCustomUserField()
;
COption::SetOptionString(
'intaro.retailcrm',
'custom_fields_toggle',
'N'
);
}
try {

View File

@ -47,7 +47,13 @@ class BitrixTestCase extends \PHPUnit\Framework\TestCase
'USER_DESCRIPTION' => 'userComment',
'COMMENTS' => 'managerComment',
'PRICE_DELIVERY' => '100',
'PROPS' => ['properties' => [['CODE' => 'FIO', 'VALUE' => ['FirstName LastName']]]],
'PROPS' => [
'properties' => [
['CODE' => 'FIO', 'VALUE' => ['FirstName LastName']],
['ID' => 1, 'CODE' => 'TEST_PROP_1', 'VALUE' => ['test 1']],
['ID' => 2, 'CODE' => 'TEST_PROP_2', 'VALUE' => ['test 2']]
]
],
'DELIVERYS' => [[
'id' => 'test',
'service' => 'service'

View File

@ -4,6 +4,7 @@ use Bitrix\Sale\Order;
use Bitrix\Currency\CurrencyManager;
use RetailCrm\Response\ApiResponse;
use Tests\Intaro\RetailCrm\DataHistory;
use CUserTypeEntity;
/**
* Class RetailCrmHistory_v5Test
@ -27,10 +28,21 @@ class RetailCrmHistory_v5Test extends \BitrixTestCase
*/
public function testRegisterUser(): void
{
RetailcrmConfigProvider::setCustomFieldsStatus('Y');
RetailcrmConfigProvider::setMatchedUserFields(
['UF_FIELD_USER_1' => 'custom_1', 'UF_FIELD_USER_2' => 'custom_2']
);
$this->registerCustomFields();
$actionsMock = Mockery::mock('alias:' . RCrmActions::class);
$apiResponse = new ApiResponse(200, DataHistory::get_history_data_new_customer());
$actionsMock->shouldReceive('apiMethod')->withAnyArgs()->andReturn($apiResponse);
$actionsMock->shouldReceive('getTypeUserField')->withAnyArgs()->andReturn([
'UF_FIELD_USER_1' => 'string', 'UF_FIELD_USER_2' => 'string'
]);
$actionsMock->shouldReceive('convertCrmValueToCmsField')->byDefault();
$this->deleteTestingUser();
RetailCrmHistory::customerHistory();
@ -38,6 +50,8 @@ class RetailCrmHistory_v5Test extends \BitrixTestCase
$dbUser = CUser::GetList(($by = 'ID'), ($sort = 'DESC'), ['=EMAIL' => 'testbitrixreg@gmail.com']);
$this->assertEquals(1, $dbUser->SelectedRowsCount());
RetailcrmConfigProvider::setCustomFieldsStatus('N');
}
/**
@ -220,4 +234,38 @@ class RetailCrmHistory_v5Test extends \BitrixTestCase
],
];
}
private function registerCustomFields()
{
$oUserTypeEntity = new CUserTypeEntity();
$userField = [
'ENTITY_ID' => 'USER',
'FIELD_NAME' => 'UF_FIELD_USER_1',
'USER_TYPE_ID' => 'string',
'MULTIPLE' => 'N',
'MANDATORY' => 'N',
'EDIT_FROM_LABEL' => ['ru' => 'TEST 1']
];
$dbRes = CUserTypeEntity::GetList([], ['FIELD_NAME' => 'UF_FIELD_USER_1'])->fetch();
if (!$dbRes['ID']) {
$oUserTypeEntity->Add($userField);
}
$userField = [
'ENTITY_ID' => 'USER',
'FIELD_NAME' => 'UF_FIELD_USER_2',
'USER_TYPE_ID' => 'string',
'MULTIPLE' => 'N',
'MANDATORY' => 'N',
'EDIT_FROM_LABEL' => ['ru' => 'TEST 2']
];
$dbRes = CUserTypeEntity::GetList([], ['FIELD_NAME' => 'UF_FIELD_USER_2'])->fetch();
if (!$dbRes['ID']) {
$oUserTypeEntity->Add($userField);
}
}
}

View File

@ -29,6 +29,8 @@ class RetailCrmOrder_v5Test extends BitrixTestCase {
*/
public function testOrderSend($arFields, $arParams, $methodApi, $expected)
{
RetailcrmConfigProvider::setCustomFieldsStatus('Y');
self::assertEquals($expected, RetailCrmOrder::orderSend(
$arFields,
new stdClass(),
@ -103,7 +105,8 @@ class RetailCrmOrder_v5Test extends BitrixTestCase {
'optionsDelivTypes' => RetailcrmConfigProvider::getDeliveryTypes(),
'optionsPayTypes' => RetailcrmConfigProvider::getPaymentTypes(),
'optionsOrderProps' => ['bitrixType' => ['fio' => 'FIO']],
'optionsPayment' => ['Y' => 'paid']
'optionsPayment' => ['Y' => 'paid'],
'customOrderProps' => ['1#TEST_PROP_1' => 'custom_first', '2#TEST_PROP_2' => 'custom_second']
];
return [[
@ -136,7 +139,8 @@ class RetailCrmOrder_v5Test extends BitrixTestCase {
'privilegeType' => 'none',
'statusComment' => $arFields['REASON_CANCELED'],
'firstName' => 'FirstName',
'lastName' => 'LastName'
'lastName' => 'LastName',
'customFields' => ['custom_first' => 'test 1', 'custom_second' => 'test 2']
],
]];
}

View File

@ -45,7 +45,9 @@ class DataHistory
"text": "Street"
},
"customFields": {
"crm_customer": "test_customer"
"crm_customer": "test_customer",
"custom_1": "test 1",
"custom_2": "test 2"
},
"segments": [],
"firstName": "Test_Name",