From 6d479ae441690180d35062dfa55e2b92902e36d0 Mon Sep 17 00:00:00 2001 From: Kocmonavtik <61938582+Kocmonavtik@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:13:31 +0300 Subject: [PATCH] =?UTF-8?q?ref=20#92774=20=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B0=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D1=81=D0=BA=D0=B8=D1=85=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9=20(#323)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 + .../classes/general/RCrmActions.php | 184 +++++++ .../classes/general/RestNormalizer.php | 2 +- .../classes/general/events/RetailCrmEvent.php | 1 + .../general/history/RetailCrmHistory_v5.php | 93 +++- .../general/order/RetailCrmOrder_v5.php | 13 +- .../classes/general/user/RetailCrmUser.php | 30 ++ intaro.retailcrm/description.ru | 2 +- intaro.retailcrm/install/version.php | 4 +- intaro.retailcrm/lang/en/options.php | 15 + intaro.retailcrm/lang/ru/options.php | 15 + .../lib/component/configprovider.php | 71 +++ intaro.retailcrm/lib/component/constants.php | 3 + intaro.retailcrm/options.php | 454 +++++++++++++++++- intaro.retailcrm/updater.php | 9 +- tests/BitrixTestCase.php | 8 +- .../history/RetailCrmHistory_v5Test.php | 48 ++ .../general/order/RetailCrmOrder_v5Test.php | 8 +- tests/datasets/DataHistory.php | 4 +- 19 files changed, 947 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98b17f2a..45b77ce6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2023-12-18 v.6.5.0 +- Добавлена поддержка функционала пользовательских полей + ## 2023-12-13 v.6.4.13 - Исправлена ошибка с получением данных программы лояльности администратора при изменении заказа в админке diff --git a/intaro.retailcrm/classes/general/RCrmActions.php b/intaro.retailcrm/classes/general/RCrmActions.php index 3667acc2..38125c8c 100644 --- a/intaro.retailcrm/classes/general/RCrmActions.php +++ b/intaro.retailcrm/classes/general/RCrmActions.php @@ -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://'; diff --git a/intaro.retailcrm/classes/general/RestNormalizer.php b/intaro.retailcrm/classes/general/RestNormalizer.php index c02986a1..86b498de 100644 --- a/intaro.retailcrm/classes/general/RestNormalizer.php +++ b/intaro.retailcrm/classes/general/RestNormalizer.php @@ -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 ]); } diff --git a/intaro.retailcrm/classes/general/events/RetailCrmEvent.php b/intaro.retailcrm/classes/general/events/RetailCrmEvent.php index 4026fab6..02b26652 100644 --- a/intaro.retailcrm/classes/general/events/RetailCrmEvent.php +++ b/intaro.retailcrm/classes/general/events/RetailCrmEvent.php @@ -175,6 +175,7 @@ class RetailCrmEvent 'optionsContragentType' => $optionsContragentType, 'optionsSitesList' => $optionsSitesList, 'optionsCustomFields' => $optionsCustomFields, + 'customOrderProps' => RetailcrmConfigProvider::getMatchedOrderProps(), ]); //many sites? diff --git a/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php index 6c6298fe..b13fe741 100644 --- a/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php +++ b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php @@ -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; + } } diff --git a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php index e5a80115..c3a5e130 100644 --- a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php +++ b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php @@ -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 = []; diff --git a/intaro.retailcrm/classes/general/user/RetailCrmUser.php b/intaro.retailcrm/classes/general/user/RetailCrmUser.php index 0561eeb9..71496ab6 100644 --- a/intaro.retailcrm/classes/general/user/RetailCrmUser.php +++ b/intaro.retailcrm/classes/general/user/RetailCrmUser.php @@ -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; + } } diff --git a/intaro.retailcrm/description.ru b/intaro.retailcrm/description.ru index e78f9750..7216b5f5 100644 --- a/intaro.retailcrm/description.ru +++ b/intaro.retailcrm/description.ru @@ -1 +1 @@ -- Исправлена ошибка с получением данных программы лояльности администратора при изменении заказа в админке +- Добавлена поддержка функционала пользовательских полей diff --git a/intaro.retailcrm/install/version.php b/intaro.retailcrm/install/version.php index 5dffb772..85150f47 100644 --- a/intaro.retailcrm/install/version.php +++ b/intaro.retailcrm/install/version.php @@ -1,6 +1,6 @@ '6.4.13', - 'VERSION_DATE' => '2023-12-13 17:00:00' + 'VERSION' => '6.5.0', + 'VERSION_DATE' => '2023-12-18 13:00:00' ]; diff --git a/intaro.retailcrm/lang/en/options.php b/intaro.retailcrm/lang/en/options.php index f9163d76..2431b3b8 100644 --- a/intaro.retailcrm/lang/en/options.php +++ b/intaro.retailcrm/lang/en/options.php @@ -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'; \ No newline at end of file diff --git a/intaro.retailcrm/lang/ru/options.php b/intaro.retailcrm/lang/ru/options.php index 67751e59..3310bf5a 100644 --- a/intaro.retailcrm/lang/ru/options.php +++ b/intaro.retailcrm/lang/ru/options.php @@ -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'] = 'Удалить'; diff --git a/intaro.retailcrm/lib/component/configprovider.php b/intaro.retailcrm/lib/component/configprovider.php index b2c27078..82f76a24 100644 --- a/intaro.retailcrm/lib/component/configprovider.php +++ b/intaro.retailcrm/lib/component/configprovider.php @@ -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)); + } } diff --git a/intaro.retailcrm/lib/component/constants.php b/intaro.retailcrm/lib/component/constants.php index d4bfb74e..38ecfc43 100644 --- a/intaro.retailcrm/lib/component/constants.php +++ b/intaro.retailcrm/lib/component/constants.php @@ -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'; } diff --git a/intaro.retailcrm/options.php b/intaro.retailcrm/options.php index f3fc958a..39365c1c 100644 --- a/intaro.retailcrm/options.php +++ b/intaro.retailcrm/options.php @@ -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')) { - BeginNextTab(); ?> + BeginNextTab(); ?> + + + +

+

+ + + + + + + + + + + +
> +
+ + + + + + + + + + + + + + $crmField) {?> + + + + + + +
+ +
+ +
+ + +      + +   + +
+ +
+ + + + + + + + + + + + + + $crmField) {?> + + + + + + +
+ +
+ +
+ + +      + +   + +
+
+ + + + + + + + +      + +   + + + + + + + + + +      + +   + + + + BeginNextTab(); ?>