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

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

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

Способ 1: Использование запроса с параметром-массивом

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

  1. Выгружаем уже имеющуюся номенклатуру из текущего документа в массив.
  2. Передаем этот массив в запрос как параметр.
  3. В тексте запроса используем условие НЕ В (&Параметр).

Рассмотрим пример кода, реализующий этот подход:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ДокументОснованиеТовары.Номенклатура КАК Номенклатура,
    |	ДокументОснованиеТовары.Количество КАК Количество,
    |	ДокументОснованиеТовары.Цена КАК Цена
    |ИЗ
    |	Документ.ЗаказПокупателя.Товары КАК ДокументОснованиеТовары
    |ГДЕ
    |	ДокументОснованиеТовары.Ссылка = &СсылкаОснование
    |	И НЕ ДокументОснованиеТовары.Номенклатура В (&СписокИсключений)";

Запрос.УстановитьПараметр("СсылкаОснование", Объект.ДокументОснование);
// Выгружаем колонку Номенклатура в массив для фильтрации
Запрос.УстановитьПараметр("СписокИсключений", Объект.Товары.ВыгрузитьКолонку("Номенклатура"));

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    НоваяСтрока = Объект.Товары.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
КонецЦикла;

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

Способ 2: Профессиональный подход с использованием временных таблиц

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

Рассмотрим по шагам, как это реализовать:

  1. Поместим текущую табличную часть документа во временную таблицу.
  2. Выполним левое соединение таблицы документа-основания с этой временной таблицей.
  3. Отберем только те записи, для которых не нашлось соответствия в текущем документе (где значение из правой таблицы ЕСТЬ NULL).

МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Шаг 1: Помещаем текущие товары во временную таблицу
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Товары.Номенклатура КАК Номенклатура,
    |	Товары.Характеристика КАК Характеристика
    |ПОМЕСТИТЬ ВТ_ТекущиеТовары
    |ИЗ
    |	&ТЧ_ТекущегоДокумента КАК Товары";
    
Запрос.УстановитьПараметр("ТЧ_ТекущегоДокумента", Объект.Товары.Выгрузить());
Запрос.Выполнить();

// Шаг 2: Сравниваем с основанием через ЛЕВОЕ СОЕДИНЕНИЕ
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ОснованиеТовары.Номенклатура,
    |	ОснованиеТовары.Характеристика,
    |	ОснованиеТовары.Количество
    |ИЗ
    |	Документ.ЗаказПокупателя.Товары КАК ОснованиеТовары
    |		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ТекущиеТовары КАК ТекущиеТовары
    |		ПО ОснованиеТовары.Номенклатура = ТекущиеТовары.Номенклатура
    |			И ОснованиеТовары.Характеристика = ТекущиеТовары.Характеристика
    |ГДЕ
    |	ОснованиеТовары.Ссылка = &СсылкаОснование
    |	И ТекущиеТовары.Номенклатура ЕСТЬ NULL";

Запрос.УстановитьПараметр("СсылкаОснование", Объект.ДокументОснование);
Выборка = Запрос.Выполнить().Выбрать();

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

Способ 3: Программный перебор с использованием метода НайтиСтроки

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

Выясним причину, почему это удобно: метод НайтиСтроки() принимает Структуру, что позволяет искать совпадение сразу по нескольким полям. Посмотрим на пример реализации:


// Получаем таблицу товаров из основания
ТаблицаОснования = Объект.ДокументОснование.Товары.Выгрузить();

Для Каждого СтрокаОснования Из ТаблицаОснования Цикл
    
    // Формируем структуру поиска
    ПараметрыПоиска = Новый Структура;
    ПараметрыПоиска.Вставить("Номенклатура", СтрокаОснования.Номенклатура);
    ПараметрыПоиска.Вставить("Характеристика", СтрокаОснования.Характеристика);
    
    // Пытаемся найти аналогичную строку в текущем документе
    НайденныеСтроки = Объект.Товары.НайтиСтроки(ПараметрыПоиска);
    
    Если НайденныеСтроки.Количество() = 0 Тогда
        // Если ничего не нашли, значит товара нет - добавляем
        НоваяСтрока = Объект.Товары.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаОснования);
    КонецЕсли;
    
КонецЦикла;

Рекомендации по оптимизации процесса

Проанализируем несколько важных моментов, которые помогут сделать код более надежным и быстрым:

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

← На главную