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