Как получить текущие остатки номенклатуры по зарегистрированным изменениям в плане обмена

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

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

Постановка задачи и базовый подход через изменения справочника

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


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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    вт.Ссылка КАК Номенклатура,
    ОстаткиНоменклатурыОстатки.КоличествоОстаток КАК КоличествоОстаток
ИЗ
    втИзменения КАК вт
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки КАК ОстаткиНоменклатурыОстатки
        ПО вт.Ссылка = ОстаткиНоменклатурыОстатки.Номенклатура

Проанализируем этот код. Во-первых, при соединении в 1С крайне не рекомендуется обращаться через точку к полям ссылочного типа в условии связи (например, вт.Ссылка.Ссылка). Это порождает лишние соединения в SQL-запросе и замедляет работу. Во-вторых, использование ЛЕВОГО СОЕДИНЕНИЯ здесь критически важно. Если товар был полностью списан в ноль, в виртуальной таблице Остатки его может просто не быть. Использование левого соединения позволит нам получить строку с товаром и значением NULL в остатке, которое мы позже преобразуем в 0.

Регистрация изменений по регистру накопления

Иногда логика задачи требует отслеживать изменения не самого справочника, а непосредственно движений в регистре. В этом случае мы обращаемся к таблице РегистрНакопления.ОстаткиНоменклатуры.Изменения. Здесь есть важный нюанс: изменения для регистров накопления всегда регистрируются в разрезе Регистратора (документа), а не конкретной номенклатуры.

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

  1. Сначала мы получаем все документы-регистраторы, которые изменились.
  2. Затем из этих документов выбираем уникальные ссылки на номенклатуру, которая в них фигурирует.
  3. На финальном этапе получаем остатки по этому списку.

Пример реализации такой логики в одном запросе:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ИзмененияРегистра.Регистратор КАК Регистратор
ПОМЕСТИТЬ втРегистраторы
ИЗ
    РегистрНакопления.ОстаткиНоменклатуры.Изменения КАК ИзмененияРегистра
ГДЕ
    ИзмененияРегистра.Узел = &Узел;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
    Движения.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ втСписокНоменклатуры
ИЗ
    РегистрНакопления.ОстаткиНоменклатуры КАК Движения
ГДЕ
    Движения.Регистратор В (ВЫБРАТЬ Регистратор ИЗ втРегистраторы);

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    вт.Номенклатура,
    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Количество
ИЗ
    втСписокНоменклатуры КАК вт
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(, 
            Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ втСписокНоменклатуры)) КАК Остатки
        ПО вт.Номенклатура = Остатки.Номенклатура

Оптимизация: работа с виртуальными таблицами

Выясним причину, почему соединение с виртуальной таблицей Остатки без параметров может работать медленно. Если база данных большая, 1С сначала попытается рассчитать остатки по всей номенклатуре, а уже потом отсечь лишнее по условию соединения.

Чтобы этого избежать, мы должны передавать список измененной номенклатуры непосредственно в параметры виртуальной таблицы. Это заставит СУБД рассчитывать итоги только по нужным нам позициям. В коде выше мы использовали конструкцию ОстаткиНоменклатуры.Остатки(, Номенклатура В (...)). Это наиболее производительный метод получения данных.

Программный интерфейс ПланыОбмена.ВыбратьИзменения

Хотя запросы к таблицам .Изменения удобны для массовой обработки, в стандартных сценариях обмена часто используется метод ПланыОбмена.ВыбратьИзменения(). Разберем его отличия:

Преимущества метода:

Преимущества запроса:

Очистка очереди изменений

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

После успешной выгрузки данных необходимо вызвать метод ПланыОбмена.УдалитьРегистрациюИзменений(). Обычно это делается либо сразу (если мы уверены в успехе), либо после получения квитанции о приеме (подтверждения) от принимающей стороны.


// Пример удаления регистрации для конкретного узла по списку
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, ДанныеОбъекта);

Резюме по шагам

Подведем итог, как эффективно решить задачу получения остатков по плану обмена:

  1. Определяем источник изменений: это может быть таблица Справочник.Номенклатура.Изменения или РегистрНакопления.ОстаткиНоменклатуры.Изменения.
  2. Формируем временную таблицу с уникальными ссылками на номенклатуру, по которой были зарегистрированы изменения.
  3. Используем эту временную таблицу как фильтр в параметрах виртуальной таблицы Остатки.
  4. Применяем ЛЕВОЕ СОЕДИНЕНИЕ и функцию ЕСТЬNULL для корректной обработки товаров, остаток которых стал равен нулю.
  5. Не забываем про очистку регистрации изменений после успешного выполнения алгоритма.

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

← На главную