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