Daniel Kasak




use PDF::ReportWriter;

my $fields = [ { name => "Company", percent => 85, font_size => 12, align => "left" }, { name => "Amount", percent => 15, font_size => 12, align => "right", aggregate_function => "sum", type => "currency" } ];

my $group = [ { name => "WeekOfMonth", data_column => 2, header => [ percent => 100, font_size => 12, align => "right", text => "Payments for week ?" ] footer => [ percent => 85, font_size => 12, align => "right", text => "Total for week ?" ], [ percent => 15, font_size => 12, align => "right", aggregate_source => 1, text => "WeekOfMonth", type => "currency" ] } ];

my $report_def = { destination => "cheques.pdf", paper => "A4", orientation => "portrait", font_list => [ "Times", "Courier" ], default_font => "Times", default_font_size => 12, x_margin => 100 * mm, y_margin => 100 * mm };

my $report = PDF::ReportWriter->new($report_def);

my $records = $dbh->selectall_arrayref( "select Company, round(Amount, 2) as Amount, case when date_format(DateReceived, '%d') between 1 and 7 then 1 when date_format(DateReceived, '%d') between 8 and 14 then 2 when date_format(DateReceived, '%d') between 15 and 21 then 3 when date_format(DateReceived, '%d') between 22 and 28 then 4 else 5 end as WeekOfMonth, date_format(DateReceived, '%W, %e %b %Y') as FullDate, 1 as LotOfOnes from Cheques where ( DateReceived between '$lower_date' and '$upper_date' ) and ( Amount is not null and Amount!=0 ) order by DateReceived");

my $data = { max_font_size => 12, cell_borders => 1, no_field_headers => 1, fields => $fields, groups => $groups, data_array => $records };



system("gpdf cheques.pdf &");


PDF::ReportWriter is designed to simplify the task of creating high-quality business reports, for archiving or printing.

All objects are rendered in cells which are defined as a percentage of the available width ( ie similar to HTML tables ).


A field definition can have the following attributes


The 'name' is used when rendering field headers, which happens whenever a new group or page is started. You can disable rendering of field headers by setting no_field_headers in your data definition ( see above example ).


The width of the field, as a percentage of the total available width. The actual width will depend on the paper definition ( size and orientation ) and the x_margin in your report_definition.


The font to use. In most cases, you would set up a report-wide default_font. Only use this setting to override the default.


The font size. Nothing special here...


Possible values are "left", "right" and "centre". Note the spelling of "centre". I'm Australian.


Possible values are "sum" and "count". Setting this attribute will make PDF::ReportWriter carry out the selected function and store the results ( attached to the field ) for later use in group footers.


The only possible value currrently is "currency".


Groups have the following attributes:


The name is used to identify which value to use in rendering aggregate functions ( see aggregate_source, below ). Also, a special name, "GrandTotals" will cause PDF::ReportWriter to fetch *Grand* totals instead of group totals. This negates the need to have an extra column of data in your data_array with all the same value ... which is the only other way I can see of 'cleanly' getting GrandTotal functionality.


The data_column refers to the column ( starting at 0 ) of the data_array that you want to group on.

Group headers and footers are defined in a similar way to field definitions ( and rendered by the same code ). The difference is that the cell definition is contained in the 'header' and 'footer' hashes, ie the header and footer hashes resemble a field hash. Consequently, most attributes that work for field cells also work for group cells. Additional attributes in the header and footer hashes are:


This is used to retrieve the results of an aggregate_function ( see above ). *** NOTE *** You MUST ( currently ) define the 'text' of a cell as the group's *name* for this to work properly. I'm working on removing thie requirement.


Possible attributes for the report defintion are:


The path to the destination ( the pdf that you want to create ).


The only paper types currently supported are A4 and Letter. And I haven't tested Letter...


portrait or landscape


An array of font names ( from the corefonts supported by PDF::API2 ) to set up. When you include a font 'family', a range of fonts ( roman, italic, bold, etc ) are created.


The name of the font type ( from the above list ) to use as a default ( ie if one isn't set up for a cell ).


The default font size to use if one isn't set up for a cell.


The amount of space ( left and right ) to leave as a margin for the report.


The amount of space ( top and bottom ) to leave as a margin for the report.


The data definition wraps up most of the previous definitions, apart from the report definition. My goal ( with a future release ) is to support unlimited 'sections', which you'll be able to achieve by passing new data definitions and calling the 'render' method. Currently this does not work, but should not take too much to get it going.

Attributes for the data definition:


This is used to calculate the required height of each row. I'm considering writing something to figure this out automatically, but for now you'll have to set this value.


Whether to render cell borders or not.


Set to disable rendering field headers when beginning a new page or group.


This is your field definition hash, from above.


This is your group definition hash, from above.


This is the data to render.


new ( report_definition )

Object constructor. Pass the report definition in.

render_data ( data_definition )

Renders the data passed in. Currently I've only tested with a single data_definition being passed and rendered, but the goal ( with a future release ) is to support rendering multiple data definitions in a single report.


Saves the pdf file ( in the location specified in the report definition ).


Dan <dan@entropy.homelinux.org>