Question

I need to generate a business report using perl + Template Toookit and LaTeX.

Things are working really well, but I am struggling with the problem of having breaks (for example page breaks, or special headers) and subtotals whenever a field changes.

So, for example, every time the field "category" changes, I'd need to have a total of sales for that category, and a header showing that another category listing is starting; and then do the same when the field "group" - with the added interest that "group" is made up of categories, so the two things should nest.

I guess anyone that has built reports with Microsoft Access (or probably any other business reporting application) should be familiar with the problem.

Ideally this would be solved at a meta-level, so I don't have to rebuild the code every time, but only to specify what fields should generate breaks or subtotals.

I am (voluntarily) constrained to LaTeX and TT: LaTeX because of the control it gives over typography, and the possibility of generating custom graphics, and TT (or anything else that works in perl) because of learning curves.

Was it helpful?

Solution

There's no built-in subtotaling feature in TT, but you could possibly put your data into a Data::Table object, that would give you some ability to handle subtotaling at the 'meta' level, as you say.

Depending on the number of columns involved though, it might be just as simple to create local hashes to maintain running totals: NB: untested, example code only

[%-
MACRO printrow(rowtype, line) BLOCK;
    # however you print the row as LaTeX
    # rowtype is 'row', 'subtotal' or 'grandtotal' for formatting purposes
END;

SET sumcols = [ 'col3', 'col4', 'col5' ]; # cols to be accumulated
SET s_tot = {}; SET g_tot = {};
FOREACH i IN sumcols;
    SET s_tot.$i = 0; # initialise
    SET g_tot.$i = 0;
END;

FOREACH row IN data;
    IF s_tot.col2 AND s_tot.col2 <> row.col2; # start of new group
        printrow('subtotal', s_tot);
        FOREACH i IN sumcols;
            SET s_tot.$i = 0; #re-init
        END;
    END;
    printrow('row', row);
    SET s_tot.col2 = row.col2; # keep track of group level

    FOREACH i IN sumcols;
        SET s_tot.$i = s_tot.$i + row.$i;
        SET g_tot.$i = g_tot.$i + row.$i;
    END;
END;
printrow('grandtotal', g_tot);
-%]

Of course, if you have more than a couple of grouping levels, this can get quite messy. You could make s_tot an array of hashes to manage each level, to avoid hard-coding the levels. That's left as an exercise for the reader, as they say.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top