© 2008 Ирина Цыбульникова
Эта статья является продолжением темы печати комплектов документов (см. Fast Report. Групповая печать и комплекты документов). Напомню, что там описывались варианты создания отчетов в виде комплекта документов, предназначенного для групповой и индивидуальной печати. Демонстрационный комплект состоял из двух документов: счета-фактуры и акта выполненных работ. С помощью этого комплекта, в том числе, была продемонстрирована групповая печать с использованием возможности композитной (пакетной) печати. На том же самом демонстрационном комплекте я покажу два других варианта групповой печати: с использованием вложенных отчетов и с использованием схемы master-detail-subdetail. Каждый из этих вариантов имеет свои достоинства и недостатки. Целью статьи является сравнение этих вариантов и раскрытие их особенностей, для того, чтобы разработчик, решающий конкретную задачу, мог выбрать подходящий для него вариант.
Новые варианты печати имеют один алгоритм подготовки данных, одну форму заказа и отличаются только построением отчетов. Главной особенностью является алгоритм подготовки данных для каждого документа из комплекта.
Структурная схема алгоритма подготовки данных

Как видно из рисунка для групповой печати комплектов будет использован запрос со списком абонентов (idsFRReport). Сформировать комплект — единственная функция этого запроса, то есть никаких данных для каждого документа этот запрос не выбирает. Сколько записей будет в этом запросе, столько комплектов и будет сформировано.
С этим главным запросом будут связаны через TDataSource заголовки счета-фактуры (idsMainInvoice) и акта выполненных работ (idsMainAct). С заголовком счета-фактуры через TDataSource связана детализация услуг (idsDtlInvoices), аналогично с заголовком акта выполненных работ связана детализация услуг акта (idsDetailAct). Если в комплект надо включить еще один документ (№3), то его тоже надо будет связать с главным запросом (idsFRReport).
Форма заказа отчета имеет следующий вид:

Теперь переходим к самому интересному — построению отчетов.
Создадим один общий отчет для всех документов комплекта. Для создания такого "комплектного" отчета воспользуемся объектами "вложенные отчеты"
![]()
Основная страница такого "комплектного" отчета имеет следующий вид:

Создадим новый отчет, положим на него бэнд MasterData1, который подключим к источнику данных frxMainDBDataset, отвечающему за формирования комплекта документов для списка абонентов. На MasterData1 расположим вложенный отчет. FastReport при этом добавил новую страницу Subreport1, связанную с MasterData1.

Включим объекту "вложенный отчет" свойство PrintOnParent, которое позволит печатать его на MasterData1, иначе невозможно будет печатать каждую счет-фактуру на отдельном листе. Также для печати каждой счета-фактуры с новой страницы установим свойство StartNewPage. На страницу Subreport1 скопируем отчет "Счет-фактура" из предыдущего примера. Внешний вид отчета счет-фактура оставим без изменений, так как он удовлетворяет ограничениям на использование вложенных отчетов. А именно, поскольку вложенный отчет формируется на основной странице отчета, то он не может содержать следующих бэндов: "Заголовок/Подвал отчета", "Заголовок/Подвал/Фон страницы", "Заголовок/Подвал колонки" (UserManual гл. 5.2).
На основной отчет положим дочерний бэнд Child1, который привяжем к MasterData1. На Child1 расположим еще один вложенный отчет, который будет отвечать за печать актов выполненных работ. Для того чтобы каждый акт печатался с новой строки, установим свойство StartNewPage бэнду Child1. Все остальные действия аналогичны действиям со счетом-фактурой. Такая структура отчета позволит выводить вначале счет-фактуру, а затем акт выполненных работ для каждого абонента из списка.

Включением/выключением каждого документа в комплекте можно управлять с помощью свойства Visible соответствующего объекта отчета. Например, если необходимо печатать только акт без счета-фактуры.
Для включения/выключения акта выполненных работ достаточно управлять свойством Visible у бэнда Child1. С включением/выключением счета-фактуры дело обстоит сложней, так как MasterData1 является главным при печати комплекта. Если ему отключить свойство Visible, то перестанет печататься привязанный к нему дочерний Child1. Выходом является управление свойством Visible у вложенного отчета Subreport1.
Например, это можно реализовать с помощью объявления переменных в отчете.
Child1.Visible := <VVisAct>;
Subreport1.Visible := <VVisInvoice>;
Но и это еще не все, так как при печати актов первая страница будет пустой. Это обусловлено тем, что на первой странице печатается пустой MasterData1 и отрабатывает свойство StartNewPage у бэнда Child1. Для того чтобы этого избежать будем управлять свойством StartNewPage у бэнда Child1.
procedure MasterData1OnBeforePrint(Sender: TfrxComponent);
begin
if (<Line> = 1) and not(<VVisInvoice>)
then Child1.StartNewPage := <VVisInvoice>
else Child1.StartNewPage := <VVisAct>;
end;
Еще одним способом печати комплектов документов является отчет с тремя уровнями данных (master-detail-subdetail). Рассмотрим построения такого отчета подробней. Создадим новый отчет, положим на него бэнд MasterData1, который подключим к источнику данных frxMainDBDataset. При помощи этого бэнда будем формировать список комплектов документов, выставленных в этом месяце. Затем положим бэнд DetailData1, который будет отвечать за печать заголовка счета-фактуры. Ниже поместим бэнд SubDetailData1, который будет отвечать за печать детализации услуг счета-фактуры. Аналогичные действия повторим для акта выполненных работ. Отчет будет иметь следующий вид:

При таком построении отчета счета-фактуры и акты выполненных работ будут выводиться на печать друг за другом без разрыва страницы.

Воспользоваться методом StartNewPage в данном случае нельзя, так как этот метод для бэндов DetailData1 и DetailData2 будет выполняться только, начиная со второй записи. Заголовок счета-фактуры и заголовок акта — первые и единственные записи каждого бэнда (в пределах текущей записи MasterData). Это нормальная работа метода StartNewPage.
Для того чтобы каждый документ выводился на новой странице, необходимо написать следующий код:
procedure DetailData2OnBeforePrint(Sender: TfrxComponent);
begin
Engine.NewPage;
end;
Описанные методы построения отчетов позволяют печатать комплекты документов для списка абонентов. Первый метод позволяет включать в комплект документов неограниченное число документов. Так как каждый документ находится на отдельной странице вложенного отчета, то его легко корректировать и управлять включением либо выключением страницы. Второй метод подходит для написания комплектов документов состоящих из небольшого числа документов, так как при большом количестве документов в комплекте, шаблон отчета становится сложным и тяжелым в управлении.
Все описанные в статье примеры можно посмотреть в архиве example.zip.
Copyright© 2008 Ирина Цыбульникова Специально для Delphi Plus