Как выгрузить последние изменения регистра накопления через веб-сервис в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При организации интеграции между 1С и внешними системами (сайтами, мобильными приложениями, внешними сервисами) часто возникает задача регулярной передачи не всей базы целиком, а только измененных данных. Если для справочников и документов логика интуитивно понятна, то работа с регистрами накопления имеет ряд тонкостей. Разберем по шагам, как правильно соединить веб-сервис и механизм планов обмена для надежной фиксации и выгрузки накопившихся движений.

Особенности фиксации изменений в регистрах накопления

Первое, на что необходимо обратить внимание, — принципиальное отличие регистров накопления от независимых регистров сведений. Регистры накопления всегда подчинены регистратору. Это означает, что система физически не может зарегистрировать изменение одной конкретной строки движения в разрезе ее измерений.

В таблице изменений регистра накопления фиксируется только ссылка на документ Регистратор, узел плана обмена и служебный номер сообщения. Проанализируем ключевые следствия этого механизма:

  1. Передается весь набор записей документа. Если в документе с сотней строк поменялась всего одна позиция, при выгрузке платформенным методом сформируется объект РегистрНакопленияНаборЗаписей целиком по данному регистратору.
  2. Очистка движений также фиксируется. Если документ отменили или пометили на удаление, в таблицу изменений попадет регистратор, а при выгрузке будет сформирован пустой набор записей с установленным отбором по этому регистратору. Внешняя система должна уметь корректно обрабатывать такие пустые наборы для удаления данных на своей стороне.
  3. Ручная регистрация выполняется через набор записей. Для ручной постановки движений в очередь вызывается метод ПланыОбмена.ЗарегистрироватьИзменения(), куда передается набор с отбором по документу. Чтение самого набора из базы перед регистрацией выполнять не требуется.

Архитектура взаимодействия веб-сервиса и плана обмена

Веб-сервисы работают по протоколу без сохранения состояния (stateless). Чтобы избежать потери данных при сетевых сбоях, удалять регистрацию изменений в момент формирования ответа нельзя. Необходимо использовать двухфазный обмен с квитированием (подтверждением приема):

  1. Идентификация клиента: внешняя система (сайт, мобильный клиент) при каждом вызове веб-сервиса передает свой уникальный код узла. В базе 1С каждому внешнему потребителю соответствует конкретный элемент (узел) плана обмена.
  2. Квитирование предыдущей сессии: вместе с кодом узла сайт присылает номер пакета, который он успешно получил и сохранил в прошлый раз (НомерПринятого). 1С очищает регистрацию только тех изменений, которые вошли в указанный подтвержденный пакет.
  3. Формирование нового пакета: система открывает запись сообщения обмена объектом ЗаписьСообщенияОбмена, что автоматически инкрементирует номер сообщения, выбирает текущие изменения и связывает их с новым номером.
  4. Передача ответа: сформированные данные вместе с новым номером сообщения возвращаются сайту. До тех пор, пока сайт в следующем запросе не пришлет подтверждение, эти записи не будут удалены из очереди и при сбое отправятся повторно.

Реализация программного интерфейса веб-сервиса

Рассмотрим пример операции веб-сервиса, которая принимает идентификатор узла и данные от внешнего устройства, удаляет подтвержденные изменения и возвращает порцию новых зарегистрированных движений.


Функция ВыполнитьОбмен(КодУстройства, НомерПринятогоСообщения) Экспорт

    УстановитьПривилегированныйРежим(Истина);
    ПланОбменаМенеджер = ПланыОбмена.ОбменСВнешнимиСистемами;
    
    // 1. Поиск или инициализация узла обмена
    УзелОбмена = ПланОбменаМенеджер.НайтиПоКоду(КодУстройства);
    Если УзелОбмена.Пустая() Тогда
        ВызватьИсключение "Узел обмена с кодом " + КодУстройства + " не найден!";
    КонецЕсли;

    // 2. Квитирование: удаление ранее успешно принятых данных
    Если НомерПринятогоСообщения > 0 Тогда
        ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, НомерПринятогоСообщения);
    КонецЕсли;

    // 3. Формирование сообщения с новыми изменениями
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.УстановитьСтроку("UTF-8");
    ЗаписьXML.ЗаписатьОбъявлениеXML();

    ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения;
    ЗаписьСообщения.НачатьЗапись(ЗаписьXML, УзелОбмена);

    // Запись пространств имен для корректной сериализации
    ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("v8", "http://v8.1c.ru/data");

    // Выбираем изменения, привязанные к новому номеру сообщения
    ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелОбмена, ЗаписьСообщения.НомерСообщения);

    Пока ВыборкаИзменений.Следующий() Цикл
        Данные = ВыборкаИзменений.Получить();
        // Данные представляют собой РегистрНакопленияНаборЗаписей
        ЗаписатьXML(ЗаписьXML, Данные);
    КонецЦикла;

    ЗаписьСообщения.ЗакончитьЗапись();
    РезультатXML = ЗаписьXML.Закрыть();

    // Возвращаем результат вызывающей стороне
    Возврат РезультатXML;

КонецФункции

Альтернативный вариант: прямая выборка через запрос к таблице изменений

Стандартный метод ПланыОбмена.ВыбратьИзменения() сериализует весь набор записей в платформенный XML. Однако внешним сервисам и веб-сайтам зачастую не требуется структура 1С со служебными тегами — им нужен плоский список строк или JSON. В таком случае мы можем обратиться напрямую к таблице изменений через язык запросов 1С.

Посмотрим на пример запроса, который соединяет зарегистрированные изменения с реальными записями регистра накопления:


ВЫБРАТЬ
    Движения.Период КАК Период,
    Движения.Регистратор КАК Регистратор,
    Движения.Номенклатура КАК Номенклатура,
    Движения.Склад КАК Склад,
    Движения.ВидДвижения КАК ВидДвижения,
    Движения.Количество КАК Количество
ИЗ
    РегистрНакопления.ОстаткиНоменклатуры.Изменения КАК ИзмененияРегистра
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры КАК Движения
        ПО ИзмененияРегистра.Регистратор = Движения.Регистратор
ГДЕ
    ИзмененияРегистра.Узел = &УзелОбмена
    И ИзмененияРегистра.НомерСообщения ЕСТЬ NULL

Проанализируем работу этого запроса. Поле НомерСообщения ЕСТЬ NULL указывает на данные, которые еще не были включены ни в один пакет передачи. Полученную выборку можно легко обойти циклом, сформировать массив структур и сериализовать в привычный для веб-разработчиков JSON через ЗаписьJSON.

Оптимизация производительности и порционная передача

Если регистр накопления активно наполняется документами, попытка выбрать все изменения разом может привести к падению рабочего процесса по нехватке памяти или к обрыву соединения веб-сервера по таймауту. Чтобы избежать этого, применим следующие рекомендации:

  1. Порционная выгрузка (пагинация): используйте конструкцию ВЫБРАТЬ ПЕРВЫЕ N в запросе по уникальным регистраторам, отдавая данные пачками по 500–1000 документов.
  2. Отключение стандартной авторегистрации: если сайту требуются движения только по определенным складам или группам номенклатуры, установите для регистра в составе плана обмена свойство Авторегистрация = Запретить.
  3. Использование подписки на события: создайте подписку на событие ПриЗаписи набора записей регистра. В обработчике проверяйте нужные условия фильтрации и вызывайте метод ПланыОбмена.ЗарегистрироватьИзменения() только тогда, когда движения действительно имеют отношение к сайту. Это защитит таблицу изменений от разрастания лишней информацией.
← На главную