При разработке производственного контура часто возникает задача автоматического расчета и заполнения табличной части Материалы на основе списка готовой продукции из табличной части Изделия и заданных норм расхода (спецификаций). Разберем по шагам, как построить надежную клиент-серверную архитектуру заполнения, сформировать корректный запрос с расчетом количества и избежать типовых ошибок.
Проанализируем работу на форме документа. Перед перезаполнением табличной части рекомендуется предупреждать пользователя о том, что существующие строки будут очищены. На управляемых формах диалоговые окна открываются асинхронно с использованием объекта ОписаниеОповещения.
Посмотрим на пример организации обработчиков команды на клиенте:
&НаКлиенте
Процедура ЗаполнитьПоСпецификации(Команда)
Если Объект.Материалы.Количество() > 0 Тогда
ТекстВопроса = НСтр("ru = 'Перед заполнением табличная часть материалов будет очищена. Продолжить?'");
Оповещение = Новый ОписаниеОповещения("ЗаполнитьПоСпецификацииЗавершение", ЭтотОбъект);
ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет,, КодВозвратаДиалога.Да);
Иначе
ЗаполнитьПоСпецификацииНаСервере();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ЗаполнитьПоСпецификацииЗавершение(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
ЗаполнитьПоСпецификацииНаСервере();
КонецЕсли;
КонецПроцедуры
Выясним причину частой ошибки начинающих разработчиков: обращение в запросе напрямую к табличной части документа в базе данных через Документ.Производство.Изделия ГДЕ Ссылка = &Ссылка. Если пользователь создал новый документ или изменил строки в форме и нажал кнопку до записи объекта, такой запрос либо вернет пустой результат, либо прочитает устаревшие данные из базы.
Чтобы алгоритм работал корректно с текущими данными формы без принудительной записи, выгрузим данные формы в таблицу значений и передадим ее в качестве параметра запроса:
&НаСервере
Процедура ЗаполнитьПоСпецификацииНаСервере()
ТаблицаИзделий = Объект.Изделия.Выгрузить();
// Если табличная часть изделий пуста, прерываем выполнение
Если ТаблицаИзделий.Количество() = 0 Тогда
Объект.Материалы.Очистить();
Возврат;
КонецЕсли;
ТаблицаМатериалов = Документы.Производство.ПолучитьТаблицуМатериаловПоСпецификациям(ТаблицаИзделий);
Объект.Материалы.Загрузить(ТаблицаМатериалов);
КонецПроцедуры
Рассмотрим подробнее логику расчета в модуле менеджера документа. Нам необходимо:
ОБЪЕДИНИТЬ ВСЕ с обязательным условием отбора по списку).Посмотрим на пример функции в модуле менеджера:
Функция ПолучитьТаблицуМатериаловПоСпецификациям(ТаблицаИзделий) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Изделие КАК Изделие,
| СУММА(Т.Количество) КАК Количество
|ПОМЕСТИТЬ ВТ_ИзделияДокумента
|ИЗ
| &ТаблицаИзделий КАК Т
|СГРУППИРОВАТЬ ПО
| Т.Изделие
|
|ИНДЕКСИРОВАТЬ ПО
| Изделие
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Спец.Ссылка КАК Ссылка,
| Спец.Материал КАК Материал,
| Спец.Количество КАК КоличествоНорма
|ПОМЕСТИТЬ ВТ_Спецификации
|ИЗ
| Справочник.ВоздуховодПрямой.Спецификация КАК Спец
|ГДЕ
| Спец.Ссылка В (ВЫБРАТЬ ВТ.Изделие ИЗ ВТ_ИзделияДокумента КАК ВТ)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| Спец.Ссылка,
| Спец.Материал,
| Спец.Количество
|ИЗ
| Справочник.Отвод.Спецификация КАК Спец
|ГДЕ
| Спец.Ссылка В (ВЫБРАТЬ ВТ.Изделие ИЗ ВТ_ИзделияДокумента КАК ВТ)
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Спецификации.Материал КАК Материал,
| СУММА(ВТ_ИзделияДокумента.Количество * ВТ_Спецификации.КоличествоНорма) КАК Количество
|ИЗ
| ВТ_ИзделияДокумента КАК ВТ_ИзделияДокумента
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Спецификации КАК ВТ_Спецификации
| ПО ВТ_ИзделияДокумента.Изделие = ВТ_Спецификации.Ссылка
|СГРУППИРОВАТЬ ПО
| ВТ_Спецификации.Материал";
Запрос.УстановитьПараметр("ТаблицаИзделий", ТаблицаИзделий);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Разберем важные нюансы, которые необходимо учитывать при реализации подобных механизмов:
ОБЪЕДИНИТЬ ВСЕ: Если не добавить фильтрацию ГДЕ Спец.Ссылка В (...) в каждый блок выборки из справочников, СУБД выполнит полное сканирование таблиц (Table Scan), что приведет к сильному падению производительности при росте базы данных.ВТ_ИзделияДокумента гарантирует корректный расчет произведения Количество * Норма без мультипликации строк при соединении.ИНДЕКСИРОВАТЬ ПО Изделие позволяет оптимизатору СУБД использовать эффективные алгоритмы соединения (например, Index Spool или Hash Match).