При работе в конфигурации "Управление производственным предприятием" (УПП) пользователи часто сталкиваются с тем, что стандартный список документов "Заказ на производство" не отображает ключевую информацию: какую именно продукцию мы собираемся производить. По умолчанию в списке видны только номер, дата и статус документа, а чтобы узнать номенклатуру, приходится открывать каждый документ. В этой статье мы подробно разберем, как вывести данные из табличной части документа в форму списка, проанализируем различные подходы и выберем наиболее оптимальный с точки зрения производительности системы.
Представим ситуацию: нам необходимо добавить в форму списка документа ЗаказНаПроизводство три колонки: Номенклатура, Спецификация и Количество. Поскольку эти данные хранятся в табличной части "Продукция", нам потребуется внести изменения в свойства формы списка.
Для начала откроем конфигуратор и выполним следующие действия:
ЗаказНаПроизводство и откроем его форму списка (обычно это ФормаСписка).Номенклатура, Спецификация, Количество.СправочникСсылка.Номенклатура, для спецификации — СправочникСсылка.СпецификацииНоменклатуры, для количества — соответствующий числовой тип.После визуальной настройки колонок они появятся в интерфейсе, но останутся пустыми. Чтобы наполнить их данными, нам нужно написать программный код в модуле формы.
Самый простой способ, который часто выбирают начинающие разработчики, — это использование обработчика события ПриВыводеСтроки. Давайте проанализируем этот метод. Это событие срабатывает каждый раз, когда строка списка отрисовывается на экране монитора.
Рассмотрим пример кода, который позволяет вывести данные первой строки табличной части в список:
Процедура СписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Проверяем, есть ли в документе хотя бы одна строка в табличной части Продукция
Если ДанныеСтроки.Ссылка.Продукция.Количество() > 0 Тогда
// Получаем первую строку табличной части
ПерваяСтрока = ДанныеСтроки.Ссылка.Продукция[0];
// Заполняем ячейки оформления значениями
ОформлениеСтроки.Ячейки.Номенклатура.Значение = ПерваяСтрока.Номенклатура;
ОформлениеСтроки.Ячейки.Спецификация.Значение = ПерваяСтрока.Спецификация;
ОформлениеСтроки.Ячейки.Количество.Значение = ПерваяСтрока.Количество;
КонецЕсли;
КонецПроцедуры
Почему это решение может быть опасным? Проанализируем ситуацию: когда вы прокручиваете список, 1С выполняет этот код для каждой видимой строки. Обращение через точку к табличной части ДанныеСтроки.Ссылка.Продукция заставляет систему делать отдельный запрос к базе данных для каждого документа. Если в списке отображается 20 строк, система сделает 20 дополнительных запросов. Это приводит к заметным задержкам ("тормозам") при работе пользователя.
Чтобы избежать проблемы "N+1 запросов", мы можем использовать событие ПриПолученииДанных. В отличие от предыдущего метода, это событие получает данные сразу для всего массива строк, которые система планирует отобразить на экране. Это позволяет нам выполнить всего один запрос к базе данных вместо десятков.
Разберем алгоритм работы в этом событии по шагам:
ОформленияСтрок и установим значения в ячейки.Посмотрим на пример реализации такого кода:
Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
МассивСсылок = Новый Массив;
Для Каждого Оформление Из ОформленияСтрок Цикл
МассивСсылок.Добавить(Оформление.ДанныеСтроки.Ссылка);
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказНаПроизводствоПродукция.Ссылка КАК Ссылка,
| ЗаказНаПроизводствоПродукция.Номенклатура КАК Номенклатура,
| ЗаказНаПроизводствоПродукция.Спецификация КАК Спецификация,
| ЗаказНаПроизводствоПродукция.Количество КАК Количество
|ИЗ
| Документ.ЗаказНаПроизводство.Продукция КАК ЗаказНаПроизводствоПродукция
|ГДЕ
| ЗаказНаПроизводствоПродукция.Ссылка В(&МассивСсылок)
| И ЗаказНаПроизводствоПродукция.НомерСтроки = 1"; // Берем только первую строку
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
Для Каждого Оформление Из ОформленияСтрок Цикл
СтрокаДанных = ТаблицаДанных.Найти(Оформление.ДанныеСтроки.Ссылка, "Ссылка");
Если СтрокаДанных <> Неопределено Тогда
Оформление.Ячейки.Номенклатура.Значение = СтрокаДанных.Номенклатура;
Оформление.Ячейки.Спецификация.Значение = СтрокаДанных.Спецификация;
Оформление.Ячейки.Количество.Значение = СтрокаДанных.Количество;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот метод работает на порядок быстрее, так как обращение к серверу базы данных происходит пакетно.
Если ваша база данных содержит сотни тысяч заказов и список все равно работает медленно, стоит рассмотреть наиболее радикальный и надежный способ. Мы можем добавить в сам документ ЗаказНаПроизводство новые реквизиты (не в табличную часть, а в "шапку"): ОсновнаяНоменклатура, ОсновнаяСпецификация и ОбщееКоличество.
Логика работы будет следующей:
ПередЗаписью, мы прописываем код, который копирует данные из первой строки табличной части в эти новые реквизиты шапки.Преимущества этого метода:
// В модуле документа ЗаказНаПроизводство
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если Продукция.Количество() > 0 Тогда
// Заполняем реквизиты шапки для отображения в списке
РеквизитНоменклатураДляСписка = Продукция[0].Номенклатура;
РеквизитКоличествоДляСписка = Продукция.Итог("Количество");
Иначе
РеквизитНоменклатураДляСписка = Справочники.Номенклатура.ПустаяСсылка();
РеквизитКоличествоДляСписка = 0;
КонецЕсли;
КонецПроцедуры
Выясним причину, по которой иногда колонки остаются пустыми, даже если код написан верно. В обычных формах 1С (как в УПП) для элементов управления в табличном поле важно проверить свойство "Данные". Если вы используете программное заполнение через ОформлениеСтроки, свойство "Данные" у колонки должно быть пустым, иначе система будет пытаться связать колонку с несуществующим полем источника данных.
Также проанализируем ситуацию с многострочными заказами. Если в одном заказе на производство указано 10 позиций номенклатуры, вывод в список только первой позиции может дезинформировать сотрудников склада или производства. В таких случаях рекомендуем использовать метод "Реквизит в шапке" и записывать туда либо самую крупную позицию, либо текстовую строку вида "Номенклатура 1, Номенклатура 2... и еще 8 позиций".
Подводя итог, можно сказать: для быстрой реализации на небольшой базе подойдет ПриВыводеСтроки с обязательной проверкой на количество строк. Для профессиональной разработки в высоконагруженных системах следует использовать ПриПолученииДанных или дублирование данных в реквизиты шапки документа.