Вывод объектов на карту в 1С Предприятие: от адреса до интерфейса

· 9 мин

Содержание

Карту в 1С делают двумя разными инструментами, и выбор зависит от задачи. Если нужно показать агрегаты по регионам России (продажи, остатки, точки присутствия) — подойдёт встроенный объект «Географическая схема», он работает без интернета и внешних ключей. Если нужны конкретные адреса контрагентов, улицы, маршруты и зоны доставки — карту подключают снаружи, через поле HTML-документа и JavaScript-API Яндекс.Карт или Google Maps.

Адреса в базе хранятся текстом, а карте нужны координаты. Поэтому между «адрес из справочника» и «точка на карте» всегда стоит один шаг — геокодирование: превращение строки адреса в пару «широта, долгота» через HTTP-запрос к сервису геокодера. Ниже — как это собрать целиком на управляемых формах платформы 8.3 в интерфейсе «Такси».

Какой инструмент выбрать и что подготовить

Сначала определитесь со способом — от этого зависит весь остальной код.

  • 🗺️ Географическая схема — родной объект платформы. Кладётся на форму как поле, источник данных — файл разметки с расширением .geo (карта регионов РФ, мира, отдельных областей). Удобна для картограмм: закрасить регионы по сумме продаж, показать пузыри по городам. Уличных адресов и спутниковых слоёв не умеет.
  • 🌐 Внешняя карта (Яндекс/Google) — HTML с JavaScript в поле HTML-документа. Умеет всё: точные адреса, метки, кластеры, маршруты, полигоны зон. Требует интернет на клиенте и API-ключ сервиса.

Для отчёта «выручка по субъектам РФ» берите географическую схему — это пять минут без ключей. Для «показать на карте всех клиентов и построить маршрут курьера» — только внешнюю карту.

Что нужно подготовить до кода:

  1. Источник точек — реквизит или справочник с адресами либо уже готовыми координатами. Если координат нет, добавьте в справочник (например, «Контрагенты» или «Склады») два реквизита типа Число с достаточной точностью: Широта и Долгота.
  2. Для внешней карты — API-ключ. У Яндекса ключи оформляются в кабинете разработчика, причём ключ для JavaScript-API и ключ для HTTP-геокодера — разные. Храните их в константах или в справочнике настроек, а не в коде модуля.
  3. Проверьте, что на клиентских машинах есть доступ в интернет к доменам сервиса — через прокси многие организации его режут.
Что именно нужно показать на карте?

Географическая схема без интернета

Самый быстрый результат, если хватает уровня «регион».

  1. На управляемую форму добавьте реквизит типа «Географическая схема» и выведите одноимённое поле.
  2. В конфигураторе или программно загрузите в неё разметку: ГеографическаяСхема.Прочитать(ИмяФайлаGeo). Файлы разметки регионов России идут в составе демо-конфигураций и в поставке платформы.
  3. Разметка состоит из серий и слоёв. Серия — это ваш показатель (например, «Выручка»), объект серии — конкретный регион. Значения расставляются в цикле по данным запроса.

Пример заливки значений по регионам из результата запроса:

Схема = Элементы.ПолеГеоСхемы.ЗначениеПоля;
ВыборкаРегионов = РезультатЗапроса.Выбрать();
Пока ВыборкаРегионов.Следующий() Цикл
    Объект = Схема.НайтиОбъект(ВыборкаРегионов.КодРегиона);
    Если Объект <> Неопределено Тогда
        Объект.УстановитьЗначение("Выручка", ВыборкаРегионов.Сумма);
    КонецЕсли;
КонецЦикла;

Названия методов разметки зависят от версии файла .geo; если точного имени не знаете, читайте структуру схемы в отладчике, а не угадывайте. Главное — механика: нашли объект-регион по коду, присвоили ему число, платформа раскрасила.

Географическая схема не требует согласования с Яндексом и не отправляет данные наружу — это её сильная сторона для внутренней аналитики.

Настройка HTTP-соединения к геокодеру

Для внешней карты всё начинается с получения координат. Геокодер — это HTTP-сервис: вы отправляете адрес строкой, получаете JSON с координатами.

Соединение по HTTPS собирается через HTTPСоединение с защищённым соединением OpenSSL. Адрес обязательно кодируется в URL — иначе пробелы и кириллица сломают запрос.

Функция ЗапроситьГеокодер(Адрес, Ключ)
    Защита = Новый ЗащищенноеСоединениеOpenSSL;
    Соединение = Новый HTTPСоединение("geocode-maps.yandex.ru", 443, , , , 30, Защита);

    Ресурс = "/1.x/?apikey=" + Ключ
        + "&format=json&results=1&geocode="
        + КодироватьСтроку(Адрес, СпособКодированияСтроки.КодировкаURL);

    Запрос = Новый HTTPЗапрос(Ресурс);
    Попытка
        Ответ = Соединение.Получить(Запрос);
    Исключение
        Возврат Неопределено; // нет сети, таймаут, недоступен хост
    КонецПопытки;

    Если Ответ.КодСостояния <> 200 Тогда
        Возврат Неопределено; // 403 — неверный ключ, 429 — превышен лимит
    КонецЕсли;

    Возврат Ответ.ПолучитьТелоКакСтроку();
КонецФункции

Разберём параметры:

  • 30 в конструкторе — таймаут в секундах. Без него зависший сервис подвесит весь сеанс пользователя.
  • КодСостояния всегда проверяйте. 403 — чаще всего неверный или непривязанный к домену ключ, 429 — вы упёрлись в суточный лимит запросов.
  • Геокодер — платный коммерческий сервис с лимитами. Не ставьте вызов геокодера в цикл по всему справочнику без задержки и кэширования — ключ заблокируют за превышение.

Запрос к геокодеру выполняется на сервере 1С (&НаСервере), а не на клиенте: на клиенте HTTPСоединение работать может, но ключ и интернет-доступ логичнее держать на стороне сервера.

Геокодирование: из адреса в координаты

Ответ геокодера — вложенный JSON. Нужные координаты лежат глубоко, но путь к ним стабильный.

Функция КоординатыИзОтвета(ТелоСтрокой)
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТелоСтрокой);
    Данные = ПрочитатьJSON(Чтение);
    Чтение.Закрыть();

    Коллекция = Данные["response"]["GeoObjectCollection"]["featureMember"];
    Если Коллекция.Количество() = 0 Тогда
        Возврат Неопределено; // адрес не распознан
    КонецЕсли;

    Поз = Коллекция[0]["GeoObject"]["Point"]["pos"]; // строка "долгота широта"
    Части = СтрРазделить(Поз, " ", Ложь);

    Результат = Новый Структура;
    Результат.Вставить("Долгота", Число(Части[0]));
    Результат.Вставить("Широта",  Число(Части[1]));
    Возврат Результат;
КонецФункции

Три момента, на которых спотыкаются чаще всего:

  • 📍 В поле pos геокодер отдаёт координаты в порядке «долгота широта» (сначала X, потом Y). А вот JavaScript-API карты принимает их наоборот — «широта долгота». Перепутаете — метка уедет в другое полушарие.
  • Пустой featureMember означает, что адрес не распознан. Такой адрес нужно пометить и дать оператору поправить вручную, а не писать в базу нули.
  • Число(Части[0]) корректно читает дробь с точкой, потому что геокодер отдаёт формат с десятичной точкой, а не запятой.

Полученные широту и долготу сохраните в реквизиты справочника. Тогда повторное построение карты пойдёт без обращения к сети — координаты уже в базе.

Отображение карты в поле HTML-документа

Теперь выводим точки. На форму кладётся поле HTML-документа, связанное с реквизитом формы типа Строка неограниченной длины (назовём его HTMLКарты). В этот реквизит пишется готовая HTML-страница с картой.

Самый надёжный способ передать точки в карту — сразу вставить их в JavaScript как массив при формировании HTML-строки на сервере. Без хрупких мостов между 1С и DOM.

&НаСервере
Процедура СформироватьКарту(ТочкиJSON)
    Макет = "<!DOCTYPE html><html><head><meta charset='utf-8'>
        |<script src='https://api-maps.yandex.ru/2.1/?apikey=КЛЮЧ&lang=ru_RU'></script>
        |<style>html,body,#map{width:100%;height:100%;margin:0}</style></head>
        |<body><div id='map'></div><script>
        |var points = %1;
        |ymaps.ready(function(){
        |  var map = new ymaps.Map('map', {center:[55.76,37.64], zoom:10});
        |  points.forEach(function(p){
        |    map.geoObjects.add(new ymaps.Placemark([p.lat, p.lon], {balloonContent:p.name}));
        |  });
        |});
        |</script></body></html>";
    HTMLКарты = СтрШаблон(Макет, ТочкиJSON);
КонецПроцедуры

Здесь ТочкиJSON — это строка вида [{"lat":55.75,"lon":37.61,"name":"Склад №1"}], которую вы собираете из справочника через ЗаписьJSON. Обратите внимание: в метку Placemark координаты идут как [lat, lon] — тот самый обратный порядок относительно геокодера.

Чтобы карта подхватила изменения, после записи строки платформа сама перерисует поле HTML-документа. Если нужно реагировать на готовность страницы (например, дождаться загрузки API перед вызовом), используйте событие поля «Документ сформирован».

Чтобы метки не слипались при сотнях точек, подключайте кластеризатор Яндекса (ymaps.Clusterer) — он сам группирует близкие метки в бабл с числом.

Для Google Maps схема та же: меняется только адрес подключаемого скрипта и имена классов (google.maps.Map, google.maps.Marker). Выбор между Яндексом и Google обычно диктует география бизнеса и условия лицензий API.

Маршруты и зоны доставки

Две самые частые надстройки над картой — маршрут между точками и полигон зоны обслуживания.

Маршрут строится мультимаршрутизатором. Передаёте массив точек (адресами или координатами), API сам прокладывает путь и считает расстояние и время.

var route = new ymaps.multiRouter.MultiRoute(
  { referencePoints: [[55.75,37.61],[55.80,37.55]], params:{routingMode:'auto'} },
  { boundsAutoApply: true }
);
map.geoObjects.add(route);

Расстояние и длительность доступны в модели маршрута после его построения — их удобно сохранить в документ «Доставка» для расчёта стоимости.

Зона доставки — это полигон. Координаты вершин зоны вы задаёте один раз (обвели район на карте) и храните в базе. Проверку «попал ли адрес клиента в зону» выполняет геометрия полигона на стороне JS, а в 1С возвращается только результат — номер зоны или признак «вне зоны».

var zone = new ymaps.Polygon([[[55.70,37.50],[55.80,37.50],[55.80,37.70]]],
  {}, {fillColor:'#1C7C5422', strokeWidth:2});
map.geoObjects.add(zone);

Для склада и курьерской логистики этого хватает: метки заказов, зоны ответственности, маршрут объезда на день.

Производительность и обработка ошибок

Карта на реальных данных упирается в два ограничения — лимиты геокодера и объём точек в браузере.

Кэшируйте координаты. Геокодируйте адрес один раз при записи элемента справочника, а не при каждом открытии карты. Если адрес не менялся — берите готовые широту и долготу из реквизитов. Это убирает 95% обращений к платному сервису.

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

Ограничивайте число меток. Несколько тысяч Placemark в браузере тормозят отрисовку. Для больших наборов включайте кластеризатор или грузите только точки, попавшие в текущую видимую область карты.

Типичные ответы геокодера и что с ними делать:

Код / симптомПричинаЧто делать
403 ForbiddenКлюч неверный или не привязан к домену/сервисуПроверить ключ в кабинете, убедиться, что это ключ геокодера, а не JS-API
429 Too Many RequestsПревышен суточный лимит запросовВключить кэш координат, разнести запросы во времени
Пустой featureMemberАдрес не распознанПометить адрес на ручную проверку оператором
Метка не там, где адресПерепутан порядок координатГеокодер даёт «долгота широта», карта ждёт «широта долгота»
Пустое поле HTMLНет интернета на клиенте или прокси режет домены APIПроверить доступ к доменам карты с рабочей станции

Если карта вообще не рисуется и в поле HTML пусто — почти всегда дело не в коде 1С, а в сети: закрыт доступ к домену API-карт или не загрузился скрипт. Откройте адрес скрипта в браузере на той же машине.

Нужен ли платный ключ, чтобы показать карту в 1С?
Для встроенной географической схемы — нет, она работает офлайн. Для Яндекс.Карт и Google Maps нужен API-ключ сервиса; у геокодера и JavaScript-карты ключи разные, причём геокодер — коммерческая услуга с лимитами.
Почему метка встаёт не на тот адрес?
Чаще всего перепутан порядок координат. Геокодер в поле pos возвращает «долгота широта», а JavaScript-API карты принимает «широта долгота». При переносе значения нужно менять местами.
Где лучше хранить координаты — считать каждый раз или в базе?
В базе. Добавьте в справочник реквизиты «Широта» и «Долгота», геокодируйте адрес один раз при записи. Повторное построение карты тогда идёт без обращения к сети и не тратит лимит геокодера.
Можно ли построить карту в толстом клиенте или только в тонком?
Поле HTML-документа работает и в тонком, и в толстом клиенте, но карте нужен интернет на клиентской машине. На сервере в фоновом задании отрисовать карту нельзя — там нет браузера; на сервере только геокодируют адреса.
Как показать не точки, а территории — например, продажи по областям?
Это задача для встроенной географической схемы с файлом разметки регионов .geo. Внешние карты для картограмм по регионам избыточны, а схема раскрасит области по значению показателя без ключей и интернета.