Как автоматически заполнить вторую табличную часть документа данными из справочника?

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

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

Постановка задачи и анализ структуры данных

Рассмотрим ситуацию: у нас есть документ ЗаказКлиента, на основании которого создается РеализацияТоваров. В документе реализации предусмотрены две табличные части:

  1. Товары — основной список (например, пиццы).
  2. Ингредиенты — детальный состав (мука, сыр, соус и т.д.).

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

Реализация через процедуру ОбработкаЗаполнения

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

Проанализируем пример кода, который выполняет перебор строк заказа и ищет соответствия в справочнике:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
    
    Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказКлиента") Тогда
        
        // Заполнение реквизитов шапки
        Покупатель = ДанныеЗаполнения.ИмяКлиента;
        Ответственный = ДанныеЗаполнения.Ответственный;
        ДокументОснования = ДанныеЗаполнения.Ссылка;
        
        // Обходим строки исходного документа Заказ Клиента
        Для Каждого ТекСтрокаЗаказ Из ДанныеЗаполнения.Заказ Цикл
            
            // Заполняем первую табличную часть "Товары"
            НоваяСтрока = Товары.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекСтрокаЗаказ);
            
            // Теперь ищем ингредиенты для текущей номенклатуры
            Запрос = Новый Запрос;
            Запрос.Текст = 
                "ВЫБРАТЬ
                |   ТК.Номенклатура КАК Ингредиент,
                |   ТК.ЕдиницыИзмерения,
                |   ТК.Склад,
                |   ТК.Расход
                |ИЗ
                |   Справочник.ТехнологическаяКарта КАК ТК
                |ГДЕ
                |   ТК.Владелец = &Владелец";
            
            Запрос.УстановитьПараметр("Владелец", ТекСтрокаЗаказ.Номенклатура);
            
            РезультатЗапроса = Запрос.Выполнить();
            
            Если НЕ РезультатЗапроса.Пустой() Тогда
                Выборка = РезультатЗапроса.Выбрать();
                Пока Выборка.Следующий() Цикл
                    // Заполняем вторую табличную часть "Ингредиенты"
                    НоваяСтрокаСостава = Ингредиенты.Добавить();
                    НоваяСтрокаСостава.Номенклатура = Выборка.Ингредиент;
                    НоваяСтрокаСостава.ЕдиницыИзмерения = Выборка.ЕдиницыИзмерения;
                    НоваяСтрокаСостава.Склад = Выборка.Склад;
                    
                    // Рассчитываем итоговый расход: норма * количество товара
                    НоваяСтрокаСостава.Количество = Выборка.Расход * ТекСтрокаЗаказ.Количество;
                КонецЦикла;
            КонецЕсли;
            
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

В данном примере мы используем метод Добавить() для каждой новой строки и функцию ЗаполнитьЗначенияСвойств для быстрого копирования реквизитов с одинаковыми именами.

Оптимизация: отказ от запроса в цикле

Важно понимать, что использование объекта Запрос внутри цикла Для Каждого является серьезной ошибкой проектирования (антипаттерн). Если в заказе будет 100 позиций, система выполнит 100 отдельных обращений к базе данных, что существенно замедлит работу. Разберем, как оптимизировать этот процесс.

Правильный алгоритм действий будет следующим:

  1. Выгружаем все уникальные товары из заказа в массив.
  2. Одним запросом получаем все ингредиенты для всех товаров из массива сразу.
  3. Используем временные таблицы для соединения данных заказа и справочника.
  4. Обходим результат запроса и распределяем данные по табличным частям.

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

Связь табличных частей через «Ключ связи»

Одной из проблем при заполнении двух таблиц является потеря визуальной связи. Если в документе две разные строки с «Пиццей Маргарита» (например, с разной ценой), как понять, какие ингредиенты относятся к первой строке, а какие ко второй? В типовых решениях для этого используется реквизит КлючСвязи.

Рассмотрим, как это работает программно:

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

Дополнительные рекомендации

Проанализируем еще несколько важных аспектов, которые сделают ваше решение профессиональным:

1. Расчет количества с учетом кратности. В справочнике «Технологическая карта» расход ингредиентов часто указывается не на 1 единицу, а на 10 или 100 порций. Не забудьте добавить в запрос поле Кратность и делить итоговое количество на это значение.

2. Использование регистров сведений. Если ваша конфигурация предполагает изменение рецептуры со временем, лучше хранить данные не в справочнике, а в периодическом регистре сведений (например, «Спецификации»). Это позволит использовать виртуальную таблицу СрезПоследних для получения актуального состава на дату документа.

3. Проверка на наличие данных. Если для товара не найдена технологическая карта, хорошим тоном будет вывести сообщение пользователю через ОбщегоНазначенияКлиентСервер.СообщитьПользователю, чтобы избежать ситуации, когда документ остается полупустым без объяснения причин.

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

← На главную