Reputation: 1428
I feed an xml file to JasperReports in order to generate a single invoice. This works fine.
However, I would also like to generate multiple invoices (i.e. all invoices for a given user) from a single xml file. The output should be just a single pdf file.
The XML file looks like this
<orders>
<order>
...
</order>
<order>
...
</order>
<order>
...
</order>
</orders>
Is this possible with JasperReports by just editing the jrxml file? I know that I could generate a pdf for each invoice by calling JasperReports in a loop. But I'd like to avoid this since it would require modifing a lot of code.
Update
I use the Jasper-Rails plugin for RoR to generate the reports. https://github.com/fortesinformatica/jasper-rails/blob/master/lib/jasper-rails/jasper_reports_renderer.rb
An xml for a single invoice is simply <order> ... </order>
The jrxml (note: xPath has already been changed to reflect mkl's approach) http://pastebin.com/R0vnrQgU
Upvotes: 0
Views: 1418
Reputation: 96064
It is possible to generate a single PDF with multiple invoices if it before was possible to generate a PDF for a single invoice.
It is not clear how many changes to the JRXML are required. Unfortunately the OP did not provide a JRXML. To illustrate a simple case:
If the order
merely contains some static amount of data and the JRXML, therefore, only essentially works on one data set, there is hardly anything to change. e.g.:
Let's assume you have original XMLs similar to this sample:
<order>
<name>Mr. Smith</name>
<quantity>2</quantity>
<item>bike</item>
<price>200</price>
</order>
and an original JRXML similar to this sample:
<queryString language="xPath">
<![CDATA[/order]]>
</queryString>
<field name="name" class="java.lang.String">
<fieldDescription><![CDATA[name]]></fieldDescription>
</field>
<field name="quantity" class="java.lang.String">
<fieldDescription><![CDATA[quantity]]></fieldDescription>
</field>
<field name="item" class="java.lang.String">
<fieldDescription><![CDATA[item]]></fieldDescription>
</field>
<field name="price" class="java.lang.String">
<fieldDescription><![CDATA[price]]></fieldDescription>
</field>
<variable name="aggregated" class="java.lang.Number">
<variableExpression><![CDATA[java.lang.Integer.parseInt($F{quantity}) * java.lang.Float.parseFloat($F{price})]]></variableExpression>
</variable>
<detail>
<band height="125" splitType="Stretch">
<textField>
<reportElement x="0" y="0" width="535" height="20"/>
<textElement/>
<textFieldExpression><![CDATA["Dear " + $F{name} + ","]]></textFieldExpression>
</textField>
<textField>
<reportElement x="0" y="40" width="100" height="20" backcolor="#CCCCCC"/>
<textElement textAlignment="Right"/>
<textFieldExpression><![CDATA[$F{quantity}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="100" y="40" width="235" height="20" backcolor="#CCCCCC"/>
<textElement textAlignment="Center"/>
<textFieldExpression><![CDATA[$F{item}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="335" y="40" width="100" height="20" backcolor="#CCCCCC"/>
<textElement textAlignment="Right"/>
<textFieldExpression><![CDATA[$F{price}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="0" y="75" width="535" height="35"/>
<textElement/>
<textFieldExpression><![CDATA["Please pay " + $V{aggregated} + " soon."]]></textFieldExpression>
</textField>
<textField>
<reportElement x="435" y="40" width="100" height="20" backcolor="#CCCCCC"/>
<textElement textAlignment="Right"/>
<textFieldExpression><![CDATA[$V{aggregated}]]></textFieldExpression>
</textField>
</band>
</detail>
Now for multi-invoice XMLs like this sample:
<orders>
<order>
<name>Mr. Smith</name>
<quantity>2</quantity>
<item>bike</item>
<price>200</price>
</order>
<order>
<name>Mr. Fisher</name>
<quantity>3</quantity>
<item>box</item>
<price>10</price>
</order>
</orders>
all you have to do in the JRXML is to change the xPath expression to match all order
elements and add a page break between data sets:
...
<queryString language="xPath">
<![CDATA[//order]]>
</queryString>
...
<detail>
<band height="125" splitType="Stretch">
...
<break>
<reportElement x="0" y="124" width="535" height="1"/>
</break>
</band>
</detail>
Even if the order
contains more dynamic data, e.g. a variable number of items, it might be just as easy as long as the order element defines the main data set (the variable number of items might be handled by some table element working on a subdataset).
After the OP provided his JRXML file, it turns out that it essentially is of the simple type indicated above. A small correction is required, though:
The OP's JRXML uses only two sections, Title and Page Footer. The latter indeed is used for page footer material but the former is not used for a title but instead for the actual invoice body, i.e. for material which shall be printed not once (as a title) but as many times as there are data sets! To make this ready for multi-invoice outputs, therefore, the title band first has to be moved to become a detail band:
...
</background>
<title>
<band height="616" splitType="Stretch">
...
</band>
</title>
<pageFooter>
...
becomes
...
</background>
<detail>
<band height="616" splitType="Stretch">
...
</band>
</detail>
<pageFooter>
...
And due to the sheer size of this band, this already suffices to make the JRXML ready for multi-order
inputs: A page break occurs automatically before the next detail section with information for the next data set because not more than one of these bands fits on a page and the band splitType
is "Stretch".
Upvotes: 1
Reputation: 189
The output into a single pdf isn't the point. The key is how to use page breaks for each invoice and the use of the headers/bands, I think.
Upvotes: 0