openxava / documentation / Report generation - Lesson 3: Master-detail report

×News: OpenXava with AI - Refine the UI (Part 2) - December 1 · Read more

Video

In this video, we will see how to create a master-detail report by receiving information from a data source in an OpenXava application.

Any problem with this lesson? Ask in the forum

Code

You can download the project for this lesson. You can also copy the code used in the video here:

In controllers.xml file:
<controller name="Invoice">
    <extends controller="Invoicing"/>
    <action name="printInvoiceDetail"
        class="com.yourcompany.invoicing.actions.PrintInvoiceDetailAction"
	mode="detail"
	icon="printer"/>
</controller>
In PrintInvoiceDetailAction.java file:
public class PrintInvoiceDetailAction extends JasperReportBaseAction {

	private Invoice invoice;
	
	@Override
	protected JRDataSource getDataSource() throws Exception {
		return new JRBeanCollectionDataSource(getInvoice().getDetails());
	}

	@Override
	protected String getJRXML() throws Exception {
		return "InvoiceDetail.jrxml";
	}

	@Override
	protected Map getParameters() throws Exception {
		Messages errors = MapFacade.validate("Invoice", getView().getValues());
		if (errors.contains()) throw new ValidationException(errors);
		Map parameters = new HashMap();			
		parameters.put("customerNumber", getInvoice().getCustomer().getNumber());
		parameters.put("customerName", getInvoice().getCustomer().getName());
		parameters.put("invoiceNumber", getInvoice().getNumber());
		parameters.put("date", getInvoice().getDate().toString());
		parameters.put("vatPercentage", getInvoice().getVatPercentage());
		parameters.put("vat", getInvoice().getVat());
		parameters.put("totalAmount", getInvoice().getTotalAmount());
		
		return parameters;
	}

	private Invoice getInvoice() {
		if (invoice == null) {
			int year = getView().getValueInt("year");
			int number = getView().getValueInt("number");
			invoice = Invoice.findByYearNumber(year, number);
		}
		return invoice;
	}
	
}
In Invoice class add the method:
 public static Invoice findByYearNumber(int year, int number) {
    Query query = XPersistence.getManager()
	    .createQuery("from Invoice as i where i.year = :year and number = :number");
    query.setParameter("year", year);
    query.setParameter("number", number);
    return (Invoice) query.getSingleResult();
}

Transcription

Hello, I'm Monica. In this lesson, we will see how to generate a master-detail report and also learn how to use a JR DataSource to send data to the report. For this, we will use the last lesson of the OpenXava course.

Today's goal will be to create a button that prints the invoice, including the detail lines. To do this, we will create the action. Since Invoice already has its controller, we define the printInvoiceDetail action directly within it. Then we will create the PrintInvoiceDetailAction action. We will also extend the JasperReportBaseAction class. Just like we did in the previous lesson, we will first send some invoice data as a parameter. However, we will slightly change the way we fetch the invoice. In the action, we will have a method that obtains the year and number values from the view and calls a findByYearNumber method that we will create in Invoice, sending the year and number as parameters. This method will search with the received values and return the invoice. Once we have the defined parameters, we set the name of the report that we will create later, and in getDataSource, we return a new JRBeanCollectionDataSource. Almost any data can be sent via data source, such as collections, maps, tables, JSON, among others. We will send the collection of details that the invoice has.

In Jaspersoft Studio, we create a new report called InvoiceDetail and proceed to declare the parameters we expect to receive. Remember that they must be of the same data type that we send from OpenXava. Once done, we drag the client and invoice data to the title zone. The summary of the detail lines goes to the column footer zone, and we remove the sections we will not use. Now it's time to deal with the collection data we receive from the data source. For this, we must create fields whose names must match the data they contain. In Detail, we have a quantity property, so we define a field named quantity. We have a product, for which we are interested in its number and description, so we define product.number and product.description. We will also include Amount and pricePerUnit. Right-click on Fields, Create field, and define the fields we mentioned one by one. Remember that they must have the same data types.

Done, we drag the fields to the detail 1 section. We can see that in the column header section, static text has been automatically created, one for each field, where each field represents a column. Below, we find a line of TextField, which shows the values of the Fields we just declared. These lines of TextField will repeat one below the other until all the elements in the collection are finished. We decorate the report a bit and copy it to the OpenXava project to test it.

We start the application. It seems that the data is displayed correctly, only some details remain, such as the percentage or currency sign where needed, or if we want to change the date format. Also, the column footer is at the end of the report, this configuration is default, but we can change it.

First, we add the currency and percentage signs. If we click outside the report, we can see in the properties panel that this report is being worked on in Java. So, to handle dates, we will do it as if we were in Java. It is worth mentioning that in date, we are receiving it as a String. So first, we define a SimpleDateFormat with the date format we want to display. But we cannot put our date directly; we must first convert it from String to date. So we use another SimpleDateFormat with the date format it has to convert it from String to date.

Finally, we want the column footer lines to appear just below the detail lines. So we click outside the report again and check the Float Column Footer option. This will make the column footer immediately follow the last detail line. With this, we are done, we save and copy the report to the project and test generating it again. These would be the results.

As mentioned in the video, you can send many types of data sources, such as collections, maps, lists, images, JSON, among others. You can also send it empty and define the data source in the report; we will see this method later. If you have any questions about this lesson, you can ask us on the forum. You can also download the code for this lesson from the repository link; both links are in the video description.

Bye.