При интеграции 1С с внешними системами (например, используя универсальный Python-коннектор к 1С, корпоративным порталом, сайтом или BI-системой) часто возникает задача инкрементальной выгрузки данных. Нам не нужно выгружать весь справочник сотрудников каждый раз — это долго и создает лишнюю нагрузку. Нам необходимо получить только тех сотрудников, данные которых изменились после определенной даты. Рассмотрим подробно, как решить эту задачу, используя стандартный интерфейс OData в платформе 1С:Предприятие, и проанализируем различные подходы к реализации.
При первом знакомстве с платформой и интерфейсом OData разработчики часто сталкиваются с тем, что в стандартной структуре справочников (например, Справочник.Сотрудники) отсутствует реквизит, отвечающий за дату и время последней записи элемента. Платформа 1С не хранит эту информацию в самой таблице справочника по умолчанию.
Если мы обратимся к сущности через OData, например, по адресу /Catalog_Сотрудники, мы получим набор полей, определенных в конфигураторе (проанализировать которые поможет генератор структуры метаданных объекта), плюс системные поля, такие как Ref_Key (уникальный идентификатор GUID), DataVersion (версия данных, но не дата) и DeletionMark. Построить фильтр вида «дай мне всех, кто изменился после 01.01.2024» без дополнительных доработок невозможно.
Разберем три основных способа решения этой задачи, от использования готовых механизмов до архитектурно правильных подходов интеграции.
В большинстве современных типовых конфигураций (1С:ЗУП, 1С:ERP, 1С:УТ) внедрена «Библиотека Стандартных Подсистем» (БСП), которая содержит функционал версионирования. Если для справочника сотрудников включено сохранение истории изменений, то при каждой записи элемента создается запись в регистре сведений.
В старых версиях БСП это регистр ВерсииОбъектов, в более новых, использующих механизмы платформы 8.3.11+, это может быть механизм ИсторияДанных. Рассмотрим вариант с регистром сведений, так как он чаще доступен для прямой публикации в OData.
Как это работает:
ВерсииОбъектов (или аналогичный) в составе OData-интерфейса.Примерная логика запроса фильтрации выглядит так: нам нужно отобрать записи, где дата версии больше нашей метки времени. Однако, у этого способа есть существенные ограничения.
Недостатки метода:
ХранилищеЗначения. OData вернет вам этот данные в виде base64 строки, внутри которой может быть сжатый XML или FastInfoSet. Распарсить это на стороне внешней системы довольно трудоемко.Тем не менее, если вам нужно просто узнать факт изменения и получить список ссылок (GUID) для последующего запроса актуальных данных, этот метод применим.
Наиболее эффективным и простым для внешней системы способом является добавление явного поля, по которому можно делать фильтрацию. Чтобы не снимать основную конфигурацию с поддержки, мы воспользуемся механизмом Расширений.
Рассмотрим алгоритм реализации:
Шаг 1. Создание расширения
Создадим новое расширение конфигурации. В него добавим заимствованный справочник Сотрудники.
Шаг 2. Добавление реквизита
В расширении к справочнику добавим новый реквизит. Назовем его, например, ДатаПоследнегоИзменения.
Тип данных: Дата (состав даты: Дата и время).
Важно: Обязательно включите свойство Индексировать для этого реквизита. Это критически важно для производительности OData-запросов, так как фильтрация будет происходить именно по этому полю.
Шаг 3. Заполнение даты при записи
Нам нужно гарантировать, что при любом изменении сотрудника (интерактивном или программном) в это поле будет попадать текущая метка времени. Для этого лучше всего использовать Подписку на событие.
ПередЗаписью для справочника Сотрудники.Пример кода в модуле подписки:
Процедура УстановитьДатуИзмененияСотрудника(Источник, Отказ) Экспорт
// Устанавливаем текущую дату сеанса (или дату сервера)
Источник.ДатаПоследнегоИзменения = ТекущаяДатаСеанса();
КонецПроцедуры
Шаг 4. Первичное заполнение
После применения расширения поле у всех существующих сотрудников будет пустым. Чтобы механизм заработал сразу для всех, необходимо написать простую обработку, которая пробежит по всем сотрудникам и заполнит это поле текущей датой или датой создания, если она известна. Это разовая операция.
Результат для OData:
Теперь сущность Catalog_Сотрудники содержит поле ДатаПоследнегоИзменения. Внешняя система может выполнять эффективные запросы вида:
GET /Catalog_Сотрудники?$filter=ДатаПоследнегоИзменения gt datetime'2023-10-25T12:00:00'
Это самый быстрый и надежный способ выборки изменений.
Платформа 1С изначально проектировалась для работы в распределенных средах, и механизм «Планов обмена» создан специально для регистрации изменений. Стандартный интерфейс OData умеет работать с планами обмена, что делает этот способ наиболее «архитектурно верным» для интеграций.
Как это реализовать:
ИнтеграцияССайтом.Сотрудники. Оставляем авторегистрацию включенной.Когда в базе данных изменяется сотрудник, платформа автоматически ставит пометку в таблице регистрации изменений для соответствующего узла. Нам не нужно писать код в подписках на события.
Получение данных через OData:
Интерфейс OData предоставляет доступ к таблицам изменений. Для получения списка измененных объектов используется специальный виртуальный ресурс.
Мы можем обратиться к ресурсу изменений плана обмена, указав GUID узла-получателя. В ответ система вернет список сущностей, которые были зарегистрированы для этого узла.
Преимущество этого метода в том, что вам не нужно хранить дату последнего опроса на стороне внешней системы. Вы просто запрашиваете «всё новое». После получения данных, внешняя система должна подтвердить прием сообщения (удалить регистрацию изменений), чтобы в следующий раз получить только новые дельты.
Однако, работа с планами обмена через OData требует более сложной логики на клиенте (чтение изменений, подтверждение получения), чем простая фильтрация по дате.
В обсуждении часто упоминается Журнал регистрации (ЖР). Важно понимать, что стандартный интерфейс OData не предоставляет доступа к данным Журнала регистрации. ЖР — это, по сути, лог-файл (или отдельные таблицы), который лежит отдельно от бизнес-данных.
Чтобы получить данные из ЖР по HTTP, вам придется писать собственный HTTP-сервис внутри конфигурации 1С, который будет программно читать журнал методами встроенного языка и сериализовать результат в JSON. Это возможно, но это уже не «коробочное» решение OData.
При любом выбранном способе (кроме HTTP-сервисов, где вы сами формируете ответ), для однозначной идентификации сотрудников следует использовать поле Ref_Key. Это уникальный идентификатор (GUID), который никогда не меняется (в отличие от Кода или Табельного номера, которые теоретически могут быть исправлены пользователем).
Подведем итог: