При разработке печатных форм в 1С часто возникает задача: не просто вывести строки табличной части на печать, но и сгруппировать информацию по определенному признаку в подвале документа. Например, нам нужно вывести номера всех строк, у которых установлен флаг Дооформление (или любое другое булево свойство), в специальное поле подвала в виде строки типа "1, 4, 12".
В этой статье мы подробно разберем, как правильно реализовать такой функционал, проанализируем распространенные ошибки разработчиков и рассмотрим несколько эффективных способов решения задачи.
Рассмотрим ситуацию, с которой часто сталкиваются начинающие программисты. Посмотрим на фрагмент кода, где разработчик пытается заполнить параметры подвала непосредственно во время обхода выборки строк табличной части:
Пока РезультатЗапроса.Следующий() Цикл
// Вывод строк табличной части
ОбластьТЧ.Параметры.НомерСтроки = РезультатЗапроса.НомерСтроки;
// ... заполнение других параметров строки ...
ТабДок.Вывести(ОбластьТЧ);
// ОШИБКА! Попытка заполнить параметры подвала внутри цикла строк
Если РезультатЗапроса.Дооформление = Истина Тогда
ОбластьПодвал.Параметры.ДооформлениеИстина = Формат(РезультатЗапроса.Дооформление,"БИ=V") + РезультатЗапроса.НомерСтроки;
КонецЕсли;
КонецЦикла;
// Вывод подвала на печать
ТабДок.Вывести(ОбластьПодвал);
Выясним причину, почему данный подход является в корне неверным. Дело в том, что область ОбластьПодвал получается один раз до начала цикла или внутри него, но выводится на печать (метод Вывести()) только после завершения всего цикла обхода строк. Когда мы на каждой итерации цикла пишем ОбластьПодвал.Параметры.ДооформлениеИстина = ..., мы просто перезаписываем значение этого параметра. В итоге в подвале отобразится информация только для самой последней строки выборки, а все предыдущие данные будут утеряны.
Также грубой ошибкой является попытка отфильтровать данные непосредственно в запросе с помощью конструкции ГДЕ АКТивныйДокументТовары.Дооформление. Если мы наложим такое жесткое условие в секции ГДЕ, наш запрос вернет только те строки, у которых флаг равен Истина. В результате в основной табличной части печатной формы пропадут все строки со значением Ложь, что нарушит целостность документа.
Для того чтобы собрать номера строк через запятую и вывести их в подвал без дублирования и перезаписи, необходимо использовать временные коллекции данных, например, Массив. Мы будем накапливать номера строк в цикле, а заполнять и выводить область подвала — строго после его завершения.
Рассмотрим по шагам правильную реализацию этого алгоритма:
Истина, второй — для Ложь.СтрСоединить(), передав в качестве разделителя запятую с пробелом.Проанализируем готовый пример кода:
ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("Макет");
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьТЧ = Макет.ПолучитьОбласть("ТЧ");
ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
// Инициализируем массивы для хранения номеров строк
МассивНомеровИстина = Новый Массив;
МассивНомеровЛожь = Новый Массив;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| АКТивныйДокументТовары.НомерСтроки КАК НомерСтроки,
| АКТивныйДокументТовары.Номенклатура.НаименованиеПолное КАК Номенклатура,
| АКТивныйДокументТовары.КоличествоПродукции КАК Количество,
| АКТивныйДокументТовары.Дооформление КАК Дооформление
|ИЗ
| Документ.АКТивныйДокумент.Товары КАК АКТивныйДокументТовары
|ГДЕ
| АКТивныйДокументТовары.Ссылка = &ТекДок";
Запрос.УстановитьПараметр("ТекДок", СсылкаНаДокумент);
РезультатЗапроса = Запрос.Выполнить().Выбрать();
// Выводим шапку один раз
ТабДок.Вывести(ОбластьШапка);
Пока РезультатЗапроса.Следующий() Цикл
// Заполняем строку табличной части
ЗаполнитьЗначенияСвойств(ОбластьТЧ.Параметры, РезультатЗапроса);
ТабДок.Вывести(ОбластьТЧ);
// Накапливаем номера строк в зависимости от флага
Если РезультатЗапроса.Дооформление Тогда
// Обязательно приводим к строке, чтобы функция СтрСоединить отработала без ошибок
МассивНомеровИстина.Добавить(Строка(РезультатЗапроса.НомерСтроки));
Иначе
МассивНомеровЛожь.Добавить(Строка(РезультатЗапроса.НомерСтроки));
КонецЕсли;
КонецЦикла;
// После цикла преобразуем массивы в читаемые строки с разделителем
СтрокаНомеровИстина = СтрСоединить(МассивНомеровИстина, ", ");
СтрокаНомеровЛожь = СтрСоединить(МассивНомеровЛожь, ", ");
// Заполняем параметры области подвала
ОбластьПодвал.Параметры.ДооформлениеИстина = СтрокаНомеровИстина;
ОбластьПодвал.Параметры.ДооформлениеЛожь = СтрокаНомеровЛожь;
// Выводим подвал в итоговый документ
ТабДок.Вывести(ОбластьПодвал);
Данный способ является наиболее производительным, так как мы получаем все необходимые данные за один проход выборки базы данных и не выполняем дополнительных запросов к серверу.
В некоторых случаях код печатной формы уже написан и зафиксирован, и вам крайне нежелательно вмешиваться в основной цикл обхода выборки. Тогда мы можем получить списки нужных номеров строк напрямую из объектной модели документа, используя метод НайтиСтроки() табличной части.
Рассмотрим, как это сделать программно:
// Получаем объект документа или его табличную часть напрямую
ТабличнаяЧастьТовары = СсылкаНаДокумент.Товары;
// Выполняем отбор строк по значению флага "Дооформление"
СтруктураОтбораИстина = Новый Структура("Дооформление", Истина);
СтрокиИстина = ТабличнаяЧастьТовары.НайтиСтроки(СтруктураОтбораИстина);
СтруктураОтбораЛожь = Новый Структура("Дооформление", Ложь);
СтрокиЛожь = ТабличнаяЧастьТовары.НайтиСтроки(СтруктураОтбораЛожь);
// Собираем номера строк для Истины
МассивИстина = Новый Массив;
Для Каждого СтрокаТЧ Из СтрокиИстина Цикл
МассивИстина.Добавить(Строка(СтрокаТЧ.НомерСтроки));
КонецЦикла;
// Собираем номера строк для Ложи
МассивЛожь = Новый Массив;
Для Каждого СтрокаТЧ Из СтрокиЛожь Цикл
МассивЛожь.Добавить(Строка(СтрокаТЧ.НомерСтроки));
КонецЦикла;
// Объединяем и передаем в параметры подвала
ОбластьПодвал.Параметры.ДооформлениеИстина = СтрСоединить(МассивИстина, ", ");
ОбластьПодвал.Параметры.ДооформлениеЛожь = СтрСоединить(МассивЛожь, ", ");
Важное примечание: Этот метод отлично подходит, если печать выполняется из модуля объекта документа, где данные табличной части уже загружены в оперативную память. Если же печать выполняется во внешней обработке или в общем модуле, где есть только ссылка на документ, этот метод вызовет дополнительное обращение к базе данных для получения объекта, что может снизить общую скорость формирования отчета при пакетной печати.
Если ваша печатная форма или отчет строятся с использованием Системы компоновки данных (СКД), то писать программный код обхода строк вообще не потребуется. Платформа 1С предоставляет мощные встроенные агрегатные функции для работы с коллекциями в СКД.
Для объединения номеров строк в одну строку с разделителем в СКД используется функция СоединитьСтроки(). В выражении ресурса или вычисляемого поля вы можете написать следующее выражение:
СоединитьСтроки(ВычислитьВыражениеТаблицыЗначений("НомерСтроки", "Дооформление = Истина"), ", ")
Давайте разберем параметры этой функции:
ВычислитьВыражениеТаблицыЗначений() — функция СКД, которая собирает массив значений из детальных записей по определенному правилу. В нашем случае мы извлекаем колонку НомерСтроки."Дооформление = Истина" — отбор, который накладывается на исходную таблицу детальных записей. Будут обработаны только те строки, где флаг установлен.", " — разделитель, с помощью которого элементы массива будут соединены в результирующую текстовую строку.Использование СКД позволяет декларативно решать подобные задачи, сокращая объем шаблонного кода на встроенном языке 1С и упрощая последующую поддержку конфигурации.
Выбирайте наиболее подходящий способ в зависимости от архитектуры вашего решения и требований к производительности системы!