Как реализовать автоматическое заполнение табличной части состава продукции на основе комплектации в 1С?

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

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

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

Анализ проблемы: почему передается только одна строка?

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


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

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

Решение №1: Работа через серверный контекст формы (рекомендуемый способ)

В управляемых формах 1С 8.3 нам не обязательно «упаковывать» данные в структуры и массивы для передачи с сервера на клиент. Мы имеем доступ к данным документа через переменную Объект прямо на сервере. Рассмотрим подробнее, как это сделать правильно.

Создадим обработчик события ПриИзменении для поля «Номенклатура» в верхней табличной части. Вызовем серверную процедуру, которая выполнит запрос и сразу заполнит подчиненную таблицу.


&НаКлиенте
Процедура СписокПродукцииНоменклатураПриИзменении(Элемент)
    ТекущаяСтрока = Элементы.СписокПродукции.ТекущиеДанные;
    Если ТекущаяСтрока <> Неопределено Тогда
        ЗаполнитьСоставНаСервере(ТекущаяСтрока.Номенклатура);
    КонецЕсли;
КонецПроцедуры

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

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

Решение №2: Использование метода ЗначениеВДанныеФормы

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

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


&НаСервере
Процедура ЗаполнитьЧерезТЗ(НоменклатураСсылка)
    // Допустим, функция где-то в общем модуле возвращает таблицу значений
    ТаблицаСостава = МодульПроизводства.РассчитатьКомплектацию(НоменклатураСсылка);
    
    // Загружаем данные из ТЗ в табличную часть объекта формы
    ЗначениеВДанныеФормы(ТаблицаСостава, Объект.СоставМатериалов);
КонецПроцедуры

Важно помнить, что метод ЗначениеВДанныеФормы полностью заменяет содержимое табличной части. Если вам нужно просто добавить строки, лучше использовать цикл или метод Загрузить для коллекции Объект.ИмяТЧ.Выгрузить().

Профессиональный подход: Учет коэффициентов и разузлование

В реальных производственных задачах состав редко бывает статичным. Разберем два критически важных момента:

  1. Пропорциональный пересчет: Если спецификация задана на 100 единиц продукции, а пользователь в документе указал 5, количество материалов должно быть пересчитано. Формула проста: (КоличествоПоСпецификации / БазоваяЕдиницаСпецификации) * КоличествоВДокументе.
  2. Разузлование: Иногда комплектующая сама является полуфабрикатом со своей спецификацией. Чтобы получить полный список «чистых» материалов, необходимо использовать рекурсивный обход или сложные запросы с использованием временных таблиц.

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


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

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

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

Рассмотрим по шагам, как улучшить UX (пользовательский опыт):

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

← На главную