При работе с Bitrix24 понадобилось сохранить адрес из Google Maps в стандартное поле Address у лида. Не просто строку, а полноценный адрес: с координатами, разбивкой на части и корректной работой всей CRM-логики.

REST API рассматривался первым, но быстро стало ясно, что в этом сценарии неудобен. Нужно было переносить адрес между сущностями Bitrix24, сохраняя связи с модулем location. REST такого контроля не даёт.

При этом в Bitrix24 уже есть стандартное поле address, связанное с Google Maps и модулем location. Оно умеет хранить координаты и структуру адреса, но в документации нет описания, как правильно заполнять его через код.

В статье разберу практический кейс: как сохранить адрес из Google Geocode во внутренние сущности Bitrix24 без REST API и без пользовательского интерфейса.

Почему стандартное поле Address сложно заполнить из кода

На первый взгляд поле Address в Bitrix24 выглядит готовым к использованию. Оно уже связано с Google Maps, умеет хранить координаты и красиво отображается в интерфейсе.

Но стоит попробовать заполнить его из кода, и начинаются сюрпризы. Простая запись текстового значения даёт только визуальный эффект. Адрес показывается, но связи с модулем location нет. Координаты не сохраняются. Структура адреса разваливается. Внутренние связи либо отсутствуют, либо выглядят странно.

Дело в том, что Address — это не одно поле. Это набор связанных сущностей и таблиц. Если заполнить их не полностью или не в том порядке, адрес перестаёт быть «живым». Он не участвует в логике CRM, его нельзя безопасно переносить между сущностями и использовать повторно.

При этом официальная документация никак не помогает. Там просто нет описания, каки�� сущности трогать и в какой последовательности, если нужен полноценный адрес, а не просто текст.

Как на самом деле хранится адрес в Bitrix24

Поле Address — это связка нескольких сущностей. При корректном сохранении они выглядят примерно так:

  • b_location — хранит externalId из Google Geocode и координаты

  • b_location_address — основная сущность адреса

  • b_location_addr_fld — разбивка адреса на части

  • b_location_addr_link — связь адреса с сущностью

  • b_crm_addr — связь адреса с CRM

Если не создать все эти записи, поле Address работает только наполовину. Простая запись строки не создаёт адрес в понимании Bitrix24.

Что нужно получить в итоге

С самого начала было важно понять, какой результат считается правильным. Речь шла не просто о заполненном поле, а о полноценной интеграции с модулем location и CRM-логикой.

В итоге адрес должен:

  • хранить latitude и longitude из Google Geocode

  • быть связан с локацией и её родителями

  • иметь разбивку на компоненты

  • спокойно переноситься между сущностями Bitrix24

  • работать как стандартное поле Address в карточке лида

И важный момент: после сохранения адрес должен без ограничений редактироваться через интерфейс, так же, как если бы его ввёл пользователь вручную.

Какие сущности участвуют в сохранении адреса

Для этого используется внутреннее API модулей location и CRM. По факту задействованы три ключевые сущности.

1. Bitrix\Location\Entity\Location

Location хранит информацию о самой локации. Здесь лежат источник данных, внешний идентификатор, координаты и тип.

При работе с Google Maps сюда передаются:

  • externalId из Google Geocode

  • источник (GOOGLE)

  • тип локации

  • координаты

  • язык

Пример инициализации:

$location = (new Location())
    ->setExternalId(...)
    ->setLatitude(...)
    ->setLongitude(...);

2. Разбивка адреса на части (fieldsCollection)

Компоненты адреса Bitrix24 хранит в виде числовых типов. Их нужно маппить вручную.

Пример соответствия компонентов Google и типов Bitrix24:

protected const LOCATION_FIELD_MAP = [
    'postal_code'                 => 50,
    'country'                     => 100,
    'administrative_area_level_1' => 200,
    'administrative_area_level_2' => 210,
    'locality'                    => 310,
    'route'                       => 340,
    'street_number'               => 400,
    'full_address'                => 410,
];

$location->setFieldValue($itemType, $itemValue);

Эти данные попадают в таблицу b_location_addr_fld и формируют структурированный адрес.

3. Bitrix\Location\Entity\Address

Address связывает локацию, координаты и компоненты адреса. Именно эта сущность делает адрес полноценным.

При создании:

  • задаются координаты

  • указывается Location

  • заполняются компоненты

  • создаётся связь с CRM

Пример:

$address = (new Address())
    ->setLatitude(...)
    ->setLongitude(...)
    ->setLocation(...);

$address->addLink('1.1.' . $leadId, 'CRM_LEAD_ADDRESS');

foreach ($fieldCollection as $itemType => $itemValue) {
    $address->setFieldValue($itemType, $itemValue);
}

4. CRM-сущность \Bitrix\Crm\EntityAddress

На финальном шаге адрес регистрируется в CRM и привязывается к лиду.

$addressFields = [
    'ADDRESS_1'    => $parts['address1'],
    'ADDRESS_2'    => $parts['address2'],
    'CITY'         => $parts['city'],
    'REGION'       => $parts['state'],
    'PROVINCE'     => $parts['province'],
    'POSTAL_CODE'  => $parts['zip'],
    'COUNTRY'      => $parts['country'],
    'COUNTRY_CODE' => $parts['country_code'],
    'LOC_ADDR_ID'  => $address->getId(),
];

\Bitrix\Crm\EntityAddress::register(
    \CCrmOwnerType::Lead,
    $leadId,
    \Bitrix\Crm\EntityAddressType::Primary,
    $addressFields
);

Адрес считается сохранённым корректно только после этого шага. Если его пропустить, CRM просто не увидит адрес.

Полный пример кода лежит здесь: https://github.com/RogSC/bitrix-address-api

Получение данных из Google Geocode

Для координат и компонентов используется Google Geocode API. Важно, чтобы данные легко ложились в модель Bitrix24.

Здесь используется серверный ключ, который уже настроен в модуле location Bitrix24. Это избавляет от дублирования конфигурации.

Получение API-ключа

function getApiKey(): string
{
    $sourceService = \Bitrix\Location\Service\SourceService::getInstance();
    $source = $sourceService->getSource();
    $config = $source->getConfig();

    return $config->getValue('API_KEY_BACKEND');
}

Используется тот же ключ, что и в интерфейсе CRM.

Вызов Google Geocode API

const URL = 'https://geocode.googleapis.com/v4beta/geocode/address/';

$httpClient = new \Bitrix\Main\Web\HttpClient([
    'version'        => '1.1',
    'socketTimeout'  => 30,
    'streamTimeout'  => 30,
    'redirect'       => true,
    'redirectMax'    => 5,
]);

$httpClient
    ->setHeader('Referer', 'https://crm.example.com/')
    ->setHeader('Content-Type', 'application/json')
    ->setHeader('X-Goog-Api-Key', getApiKey());

function geocodeAddress(string $address): array
{
    $url = self::URL . urlencode($address);
    $response = $httpClient->get($url);

    return Json::decode($response);
}

На выходе — координаты, placeId и компоненты адреса.

Последовательность сохранения адреса

Порядок здесь критичен. Если его нарушить, связи ломаются.

Общая схема такая:

  1. Создать Location

  2. Записать компоненты адреса

  3. Создать Address

  4. Зарегистрировать адрес в CRM

Шаг 1. Location

$location = (new Location())
    ->setExternalId((string)$data['externalId'])
    ->setSourceCode('GOOGLE')
    ->setType(Location\Type::ADDRESS_LINE_1)
    ->setName($data['name'])
    ->setLanguageId('en')
    ->setLatitude($data['latitude'])
    ->setLongitude($data['longitude']);

Шаг 2. Компоненты адреса

foreach ($fieldCollection as $itemType => $itemValue) {
    $location->setFieldValue($itemType, $itemValue);
}

$location->save();

Шаг 3. Address

$address = (new Address('en')) //languageId
    ->setLatitude($parts['lat'])
    ->setLongitude($parts['lon'])
    ->setLocation($location);

$address->addLink('1.1.' . $leadId, 'CRM_LEAD_ADDRESS');

foreach ($fieldCollection as $itemType => $itemValue) {
    $address->setFieldValue($itemType, $itemValue);
}

$address->save();

Шаг 4. Регистрация в CRM

\EntityAddress::register(
    \CCrmOwnerType::Lead,
    $leadId,
    \Bitrix\Crm\EntityAddressType::Primary,
    [
        'ADDRESS_1'    => $parts['address1'],
        'ADDRESS_2'    => $parts['address2'],
        'CITY'         => $parts['city'],
        'REGION'       => $parts['state'],
        'PROVINCE'     => $parts['province'],
        'POSTAL_CODE'  => $parts['zip'],
        'COUNTRY'      => $parts['country'],
        'COUNTRY_CODE' => $parts['country_code'],
        'LOC_ADDR_ID'  => $address->getId(),
    ]
);

После этого адрес полностью работает в CRM.

Проверка результата

Проверить всё можно двумя способами: в базе и в интерфейсе.

b_location
Там появляется запись с EXTERNAL_ID, источником GOOGLE и координатами.

b_location_addr_fld
Здесь видно, что адрес реально разложен по частям, а не хранится одной строкой.

Связи с CRM
В b_crm_addr появляется связь с CRM-сущностью и LOC_ADDR_ID.

Карточка лида
В интерфейсе адрес выглядит как обычное поле Address. Его можно редактировать, Google Maps работает как обычно.

Подводные камни

Есть несколько моментов, о которых лучше знать заранее.

Зависимость от внутреннего API
Сущности не публичные. Обновления Bitrix24 могут что-то сломать.

Порядок важен
Нарушил последовательность — потерял связи.

Типы полей (b_location_addr_fld)
Ошибся в маппинге — адрес выглядит нормально, но структура не сохраняется.

Язык
languageId влияет на нормализацию адреса.

Google API
Следи за лимитами, особенно при массовой обработке.

Итоги

Поле Address в Bitrix24 — это не текст, а набор связанных сущностей. Чтобы заполнить его корректно, нужно работать с внутренним API и соблюдать порядок действий.

Этот подход позволяет сохранить адрес из Google Geocode полностью: с координатами, структурой и рабочей интеграцией с CRM. Адрес ведёт себя так же, как введённый вручную.

Решение не использует REST API и оправдано в сценариях, где важно сохранить все связи и переносить адреса между сущностями. Для простых задач REST может быть проще.

Код с минимальной реализацией лежит в репозитории: https://github.com/RogSC/bitrix-address-api