You can use SinglePageTemplate instead of DocumentBuilder for single page document generation. The SinglePageTemplate class provides a specialized api that simplifies the generation of single page documents.

You can read more about FO elements at datypic.

1 Lambda template functions

The SinglePageTemplate defines 7 FOP area blocks. From those,

  • Five are specifically related to FOP regions (start, end, before, after, body).
  • One is specifically designed to setup document (root).
  • and one is designed for last page body flow content (bodyfootnote).

You can setup a javascript lambda function to provide configuration and content for each of those area blocks. This method simplifies the process of document generation as you will only need to focus on each concrete area.

Section Argument Description
Root FOPRoot Provides a way to setup document layout. This function is called first and it's not specifically related to any FOP area but a way to configure the document.
Start FOPStaticContent Defines the content of start region, repeated on each page.
End FOPStaticContent Defines the content of end region, repeated on each page.
Before FOPStaticContent Defines the content of before region, repeated on each page.
After FOPStaticContent Defines the content of after region, repeated on each page.
Body FOPFlow Defines the content of body flow.
BodyFootNote FOPFootNote Defines the content of body footnote section. This is a block displayed at the end of the body flow.

2 Basic page layout

Let's start generating a simple page layout. We will setup debug("*") with indicates we want to highlight (mark) all FOP components.

For better understanding you should use debug during layout prototyping and even look on FOP xml content.

Copy
<script>

    var template = new Ax.fop.SinglePageTemplate("A4");
    
    // =======================================================================
    // CONFIGURE FOP ROOT LAYOUT
    // =======================================================================
    
    template.setRoot(root => {
        // setup debug on all components
    	root.setDebug("*");
    	root.getSimplePageMaster().getRegionBefore().setExtent(8.5);
    	root.getSimplePageMaster().getRegionAfter().setExtent(1.5);
    	root.getSimplePageMaster().getRegionStart().setExtent(1.0);
    	root.getSimplePageMaster().getRegionEnd().setExtent(1.0);
    	root.getSimplePageMaster().setMargins(0, 0, 0, 0);
    });
    
    // ====================================================================
    // GENERATE PDF
    // ====================================================================
    
    var fop = template.toFOP();
    let pdf = new Ax.fop.Processor().transform(fop);
    let doc = new Ax.io.File("/tmp/Layout.pdf");
    doc.write(pdf);
    return pdf;
</script>

3 Template model

A complete template model will look like the code below. Each region may provide it's content by adding content to the provided container.

Copy
<script>

    var template = new Ax.fop.SinglePageTemplate("A4");
    
    // =======================================================================
    // CONFIGURE FOP ROOT LAYOUT
    // =======================================================================
    
    template.setRoot(root => {
        //root.setDebug("*");
        root.getSimplePageMaster().getRegionBefore().setExtent(8.5);
        root.getSimplePageMaster().getRegionAfter().setExtent(1.5);
        root.getSimplePageMaster().getRegionStart().setExtent(1.0);
        root.getSimplePageMaster().getRegionEnd().setExtent(1.0);
        root.getSimplePageMaster().setMargins(0, 0, 0, 0);
    });

    // =======================================================================
    // SET START REGION CONTENT
    // =======================================================================
    template.setStart(start => {
        // TODO
    });
    
    // =======================================================================
    // SET END REGION CONTENT
    // =======================================================================
    template.setEnd(end => {
        // TODO
    });
    
    // =======================================================================
    // SET BEFORE REGION CONTENT
    // =======================================================================
    template.setBefore(before => {
        // TODO
    });
    
    // =======================================================================
    // SET AFTER REGION CONTENT
    // =======================================================================
    template.setAfter(after => {
        // TODO
    });
    
    // =======================================================================
    // SET BODY FLOW CONTENT
    // =======================================================================
    template.setBody(body => {
        // TODO
    });
    
    // =======================================================================
    // SET BODY FOOT NOTE CONTENT
    // =======================================================================
    template.setBodyFootNote(footnote => {
        // TODO
    });
    
    // ====================================================================
    // GENERATE PDF
    // ====================================================================
    
    var fop = template.toFOP();
    //console.log(fop);
    let pdf = new Ax.fop.Processor().transform(fop);
    
    // Either write to file
    let doc = new Ax.io.File("/tmp/sample-debug.pdf");
    // or return to caller
    doc.write(pdf);
    return pdf;

</script>

4 Adding content before

Let's see how to add content on before region. To do that we simply need to add a lambda function for the before region.

Copy
<script>
    var FILE_PATH = "https://bitbucket.org/deister/axional-docs-resources/raw/master/FOP/Invoices/Style1";
    
    var SVG_WATERMARK =
        "<svg:svg width='600' height='300' xmlns:svg='http://www.w3.org/2000/svg'>\n"+
        "  <svg:g transform='rotate(-30)'>\n"+
        "    <svg:text x='0' y='300' style='font-family:Courier;font-size:140;font-weight:normal;stroke-width:0.5;fill:#EDEDED;stroke:lightgray;stroke-opacity:0.75;'>\n"+
        "        COPY\n"+
        "    </svg:text>\n"+
        "  </svg:g>\n"+
        "</svg:svg>\n";
	    
    var template = new Ax.fop.SinglePageTemplate("A4");
    
    
    // =======================================================================
    // COLORS
    // =======================================================================
    var COLOR_LIGHT_GRAY = "#6d6d6d";
    var COLOR_TABLE_HEADER_GREEN = "#8BB260";
    var COLOR_TABLE_FOOTER_BLUE  = "#1d6480";
    var COLOR_LINE = "#eeeeee";
    
    // =======================================================================
    // FONTS
    // =======================================================================
    var FONT_NAME = "Noto Sans";
    var	FONT_SIZE_TITLES = 14;
    var	FONT_SIZE_TABLE_HEAD = 9;
    var	FONT_SIZE_TABLE_BODY = 8;
    
    // =======================================================================
    // CONFIGURE FOP ROOT LAYOUT
    // =======================================================================
    
    template.setRoot(root => {
        //root.setDebug("*");
        root.getSimplePageMaster().getRegionBefore().setExtent(8.5);
        root.getSimplePageMaster().getRegionAfter().setExtent(1.5);
        root.getSimplePageMaster().getRegionStart().setExtent(1.0);
        root.getSimplePageMaster().getRegionEnd().setExtent(1.0);
        root.getSimplePageMaster().setMargins(0, 0, 0, 0);
    });

    // =======================================================================
    // SET START REGION CONTENT
    // =======================================================================
    template.setStart(start => {
        // TODO
    });
    
    // =======================================================================
    // SET END REGION CONTENT
    // =======================================================================
    template.setEnd(end => {
        // TODO
    });
	
    // =======================================================================
	// SET BEFORE REGION CONTENT
    // =======================================================================
    template.setBefore(before => {
    
        before.addBlockContainer()
            //.setBorderColor("red").setBorderStyle("solid")
            .setPosition("absolute")
            .setTop("12.5cm")
            .setLeft("0.0cm")
            .addBlock()
            .addInstreamForeignObject(SVG_WATERMARK);

        var table = before.addTable();
        table.setFontFamily(FONT_NAME);
        table.setFontSize(FONT_SIZE_TABLE_HEAD);
        table.addColumn();
        table.addColumn();
        
        var row1 = table.getBody().addRow();
        var c11 = row1.addCell();
        var c12 = row1.addCell();
        c11.addBlock().addExternalGraphic(FILE_PATH + "/logo-left.png").setContentWidth(6.0);
        c12.addBlock().setTextAlign("center").addExternalGraphic(FILE_PATH + "/logo-right.png").setContentWidth(8.0);
        
        var row2 = table.getBody().addRow();
        var c21 = row2.addCell();
        var c22 = row2.addCell();
        
        c21.setDisplayAlign("center");
        c21.setPaddingLeft("36pt");
        c21.addBlock("Customer").setFontWeight("bold").setFontSize(FONT_SIZE_TITLES).setColor(COLOR_TABLE_HEADER_GREEN);
        
        c22.setPadding("20pt");
        c22.setDisplayAlign("center");
        c22.setBorderTopStyle("solid");
        c22.setBorderTopColor(COLOR_LIGHT_GRAY);
        c22.setBorderBottomStyle("solid");
        c22.setBorderBottomColor(COLOR_LIGHT_GRAY);
        c22.addBlock("Balace Due").setFontWeight("bold").setFontSize(FONT_SIZE_TITLES).setColor(COLOR_TABLE_HEADER_GREEN);;
    
    });

    // =======================================================================
    // SET AFTER REGION CONTENT
    // =======================================================================
    template.setAfter(after => {
        // TODO
    });
    
    // =======================================================================
    // SET BODY FLOW CONTENT
    // =======================================================================
    template.setBody(body => {
        // TODO
    });
    
    // =======================================================================
    // SET BODY FOOT NOTE CONTENT
    // =======================================================================
    template.setBodyFootNote(footnote => {
        // TODO
    });
    
    // ====================================================================
    // GENERATE PDF
    // ====================================================================
    
    var fop = template.toFOP();
    console.log(fop);
    let pdf = new Ax.fop.Processor().transform(fop);
    let doc = new Ax.io.File("/tmp/Invoice1.pdf");
    doc.write(pdf);
    return pdf;

</script>

5 Page sequence

Documents can be longer than one page. Sometimes you may be interested in defining different properties depending on the position of the page.

  • There are four position: only, first, rest and last.
  • The only position corresponds to single-page documents.
  • The first position corresponds the first document page.
  • The rest position corresponds to pages that are neither the first nor the last.
  • The last position corresponds the last document page.

To do it is defined one master page for each position. And in each region content(before, after, start, end) the properties of each ot the master pages are defined.

Copy
var template = new Ax.fop.SinglePageTemplate("A4");

// =======================================================================
// CONFIGURE FOP ROOT LAYOUT
// =======================================================================
template.setRoot(root => {

    // Default Master Page layout    
    root.getSimplePageMaster().getRegionBefore().setExtent(1.5);
    root.getSimplePageMaster().getRegionAfter().setExtent(1.5);
    root.getSimplePageMaster().getRegionStart().setExtent(1.0);
    root.getSimplePageMaster().getRegionEnd().setExtent(1.0);
    root.getSimplePageMaster().setMargins(0, 0, 0, 0);
    
    // ===================================================================
    // Define four SIMPLE PAGE MASTER with his properties: 
    // PageOnly 
    // PageFirst 
    // PageRest 
    // PageLast
    // ===================================================================

    // Get the FOPSimplePageMaster now (we only have one)
    // after adding the first .. we can not call again
    // cause we have two ... and dont know witch one ..
    var spm = root.getSimplePageMaster();

    var pageOnly  = root.addSimplePageMaster("PageOnly").apply(spm);
    var pageFirst = root.addSimplePageMaster("PageFirst").apply(spm);
    var pageRest  = root.addSimplePageMaster("PageRest").apply(spm);
    var pageLast  = root.addSimplePageMaster("PageLast").apply(spm);

    pageOnly.getRegionBefore().setBackgroundColor("Azure").setExtent(3);
    pageOnly.getRegionAfter().setBackgroundColor("Azure").setExtent(3);
    pageOnly.getRegionStart().setBackgroundColor("LightGreen").setExtent(3);
    pageOnly.getRegionEnd().setBackgroundColor("LightGreen").setExtent(3);
    pageOnly.getRegionBody().setBackgroundColor("MistyRose");

    pageFirst.getRegionBefore().setBackgroundColor("Azure").setExtent(3);
    pageFirst.getRegionAfter().setBackgroundColor("Azure").setExtent(3);
    pageFirst.getRegionStart().setBackgroundColor("LightGreen").setExtent(3);
    pageFirst.getRegionEnd().setBackgroundColor("LightGreen").setExtent(3);
    pageFirst.getRegionBody().setBackgroundColor("MistyRose");

    pageRest.getRegionBefore().setBackgroundColor("Azure").setExtent(6);
    pageRest.getRegionAfter().setBackgroundColor("Azure").setExtent(6);
    pageRest.getRegionStart().setBackgroundColor("LightGreen").setExtent(6);
    pageRest.getRegionEnd().setBackgroundColor("LightGreen").setExtent(6);
    pageRest.getRegionBody().setBackgroundColor("MistyRose");

    pageLast.getRegionBefore().setBackgroundColor("Azure").setExtent(9);
    pageLast.getRegionAfter().setBackgroundColor("Azure").setExtent(9);
    pageLast.getRegionStart().setBackgroundColor("LightGreen").setExtent(9);
    pageLast.getRegionEnd().setBackgroundColor("LightGreen").setExtent(9);
    pageLast.getRegionBody().setBackgroundColor("MistyRose");

    // ===================================================================
    // Create a PAGE SEQUENCE MASTER, assign a page position to each page master:
    // master page PageOnly  is only one page (last = first)
    // master page PageFirst is the first page
    // master page PageRest are the rest pages
    // master page PageLast  is the last page
    // ===================================================================

    var master = root.createPageSequenceMaster("master");    

    master.addConditionalPageMasterReference(root.getSimplePageMaster("PageOnly"),  "only");
    master.addConditionalPageMasterReference(root.getSimplePageMaster("PageFirst"), "first");
    master.addConditionalPageMasterReference(root.getSimplePageMaster("PageRest"),  "rest");
    master.addConditionalPageMasterReference(root.getSimplePageMaster("PageLast"),  "last");
    root.addPageSequenceMaster(master);
    root.getPageSequence().setMasterReferenceName("master");
});

// =======================================================================
// SET BEFORE REGION CONTENT
// =======================================================================
template.setBefore(before => {

    switch(before.getMasterName()) {
        case "PageOnly":
            before.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("Before region only one page");
            break;        
        case "PageFirst":
            before.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("Before region first page");
            break;
        case "PageRest":
            before.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("Before region rest page");
            break;
        case "PageLast":
            before.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("Before region last page");
            break;
    }    
});

// =======================================================================
// SET AFTER REGION CONTENT
// =======================================================================
template.setAfter(after => {
    switch(after.getMasterName()) {
        case "PageOnly":
            after.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("After region only one page");
            break;        
        case "PageFirst":
            after.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("After region first page");
            break;
        case "PageRest":
            after.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("After region rest page");
            break;
        case "PageLast":
            after.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("After region last page");
            break;
    }    
})

// =======================================================================
// SET START REGION CONTENT
// =======================================================================
template.setStart(start => {

    switch(start.getMasterName()) {
        case "PageOnly":
            start.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("Start region only one page");
            break;        
        case "PageFirst":
            start.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("Start region first page");
            break;
        case "PageRest":
            start.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("Start region rest page");
            break;
        case "PageLast":
            start.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("Start region last page");
            break;
    }    
});

// =======================================================================
// SET end REGION CONTENT
// =======================================================================
template.setEnd(end => {

    switch(end.getMasterName()) {
        case "PageOnly":
            end.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("End region only one page");
            break;
        case "PageFirst":
            end.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("End region first page");
            break;
        case "PageRest":
            end.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("End region rest page");
            break;
        case "PageLast":
            end.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")
            .addTextLiteral("End region last page");
            break;
    }    
})

// =======================================================================
// SET BODY REGION CONTENT
// =======================================================================
template.setBody(body => {
    body.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center").setPageBreakAfter("always")                
        .addTextLiteral("Body region");

    body.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center").setPageBreakAfter("always")                
        .addTextLiteral("Body region");

    body.addBlock().setPaddingTop("10pt").setFontSize(12).setTextAlign("center")               
        .addTextLiteral("Body region");
})

var fop = template.toFOP();
let pdf = new Ax.fop.Processor().transform(fop);

let doc = new Ax.io.File("/tmp/Invoice1.pdf");
doc.write(pdf);
return pdf;
Click here to download the PDF example

You can also set even-odd page layout by using page sequences. There are three positions:

  • The first position corresponds the first document page.
  • The even position corresponds to even pages in flow.
  • The odd position corresponds to odd pages in flow.
Copy
// ====================================================================
// Define the document using 3 page master pages
// ====================================================================
var root = new Ax.fop.DocumentBuilder()
	.addSimplePageMaster("PageMaster_First", 0.5, 0.5, 0.5, 1.0)
	.addSimplePageMaster("PageMaster_Even",  1.5, 1.5, 1.5, 1.0)
	.addSimplePageMaster("PageMaster_Odd",   2.5, 2.5, 0.5, 1.0)
.build();

root.getPageMaster("PageMaster_First").getRegionBefore().setExtent(2.0);
root.getPageMaster("PageMaster_Even").getRegionBefore().setExtent(3.0);
root.getPageMaster("PageMaster_Odd").getRegionBefore().setExtent(3.0);

// ====================================================================
// Define the page sequence, first, even, odd
// ====================================================================
root.addPageSequenceMaster("DoublePageMaster")
	.addSimplePageMaster("PageMaster_First", "first")
	.addSimplePageMaster("PageMaster_Even",  "even")
	.addSimplePageMaster("PageMaster_Odd",   "odd");

// ====================================================================
// Add a page sequence. This will generate a FLOW for given name
// ====================================================================
root.addPageSequence("DoublePageMaster");

wrapper_first_before = root.getStaticContentBefore("PageMaster_First").getWrapper();
wrapper_first_before.addBlock("First Page")
wrapper_even_before  = root.getStaticContentBefore("PageMaster_Even").getWrapper();
wrapper_even_before.addBlock("Even Page")
wrapper_odd_before   = root.getStaticContentBefore("PageMaster_Odd").getWrapper();
wrapper_odd_before.addBlock("Odd Page")

var wrapper = root.getBodyFlow("DoublePageMaster").getWrapper();
for (let x = 0; x < 200; x++) {
    wrapper.addBlock("Future Generation Computer Systems 28 (2012) 861–870");
}

var fop = root.toFOP();
let pdf = new Ax.fop.Processor().transform(fop);
return pdf;

6 Invoice Examples

Now we are ready to complete a full invoice example using the knowlege from previous section.

6.1 Invoice 1 example

The following example provides full set of SinglePageTemplate features to generate a complete Invoice.

Copy

Example

<script>

var FILE_PATH   = "https://bitbucket.org/deister/axional-docs-resources/raw/master/FOP/Invoices/Style1";

// =======================================================================
// COLORS
// =======================================================================
var COLOR_LIGHT_GRAY = "#6d6d6d";
var COLOR_TABLE_HEADER_GREEN = "#8BB260";
var COLOR_TABLE_FOOTER_BLUE  = "#1d6480";
var COLOR_LINE = "#eeeeee";

// =======================================================================
// FONTS
// =======================================================================
var FONT_NAME = "Noto Sans";
var	FONT_SIZE_TITLES = 14;
var	FONT_SIZE_TABLE_HEAD = 9;
var	FONT_SIZE_TABLE_BODY = 8;

// =======================================================================
// FORMATS
// =======================================================================
var	NUMBER_FORMAT = "%,.2f";
var	DATE_FORMAT = "MMM, dd, yyyy";

// =======================================================================
// DATA
// =======================================================================
var m_locale = "us";
var m_data =  {

	"SVG_WATERMARK" :
		"<svg:svg width='600' height='300' xmlns:svg='http://www.w3.org/2000/svg'>\n"+
	    "  <svg:g transform='rotate(-30)'>\n"+
	    "    <svg:text x='0' y='300' style='font-family:Courier;font-size:140;font-weight:normal;stroke-width:0.5;fill:#EDEDED;stroke:lightgray;stroke-opacity:0.75;'>\n"+
	    "        COPY\n"+
	    "    </svg:text>\n"+
	    "  </svg:g>\n"+
	    "</svg:svg>\n",
	    
	 "m_from" : {
	 
		"m_company" 	: "Cameset Print Solutions",
		"m_address1" 	: "4141 Hacienda Dr",
		"m_address2"	: "Pleasanton California 94588",
		"m_address3"	: "U.S.A",
		"m_phone"		: "+563 1200 4569\n(33) 785 9865 4789",
		"m_email"		: "cameset@gmail.com\nwww.cameset.com",
	 },

	 "m_to" : {
		"m_company"		: "Fantasy Comics",
		"m_person"		: "Jhon Doe",
		"m_address1"	: "1301 K Street NW",
		"m_address2"	: "Washington D.C.",
		"m_address3"	: "U.S.A",
	 },


	 "m_invoice" : {
		"m_order"		: "#R337284",
		"m_number"		: "INV-2020/17",
		"m_balance_due"	: 2700.0,		// must be floating point to be handled by %f
		"m_date_invoice": new Ax.sql.Date(),
		"m_date_due"	: new Ax.sql.Date(),
		"m_terms"		: "Due On Receipt",
	 },
}

	var LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
    var m_resultset = new Ax.rs.Reader().build(
    	[
			[ "Web Design", 15, 10, "Hour", 150, LOREM ],
			[ "Graphic Design", 29, 50, "Pcs", 1450, LOREM],
			[ "Brand Identity", 35, 10, "Pcs", 350, LOREM],
			[ "Magazie Design", 11, 50, "Pcs", 550, LOREM],
			[ "Flyer Design", 10, 20, "Pcs", 200, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
			[ "Empty", 0, 0, "Pcs", 0, LOREM],
    	], 
    	options => {
	        options.setColumnNames(
	        	[
					"DESCRIPTION",
					"QTY",
					"RATE",
					"UNIT",
					"SUBTOTAL",
					"TEXT"
		 		]
		    );
    	}
    );

var template = new Ax.fop.SinglePageTemplate("A4");


// =======================================================================
// CONFIGURE FOP ROOT LAYOUT
// =======================================================================

template.setRoot(root => {
	//root.setDebug("*");
	root.getSimplePageMaster().getRegionBefore().setExtent(8.5);
	root.getSimplePageMaster().getRegionAfter().setExtent(1.5);
	root.getSimplePageMaster().getRegionStart().setExtent(1.0);
	root.getSimplePageMaster().getRegionEnd().setExtent(1.0);
	root.getSimplePageMaster().setMargins(0, 0, 0, 0);

});

// =======================================================================
// CONFIGURE START
// =======================================================================

template.setStart(start => {
	start.addBlock().setPaddingTop("10pt").setFontFamily(FONT_NAME).setFontSize(8).setTextAlign("center")
		.addTextLiteral("&#x00A9; 2020 deister software");

});

// =======================================================================
// CONFIGURE END
// =======================================================================
template.setEnd(end => {
	end.addBlock().setPaddingTop("10pt").setFontFamily(FONT_NAME).setFontSize(8).setTextAlign("center")
		.addTextLiteral("&#x00A9; 2020 deister software");

});

// =======================================================================
// CONFIGURE BEFORE
// =======================================================================
template.setBefore(before => {

	before.addBlockContainer()
		//.setBorderColor("red").setBorderStyle("solid")
		.setPosition("absolute")
		.setTop("12.5cm")
		.setLeft("0.0cm")
		.addBlock()
		.addInstreamForeignObject(m_data.SVG_WATERMARK);
	
	var table = before.addTable();
	table.setFontFamily(FONT_NAME);
	table.setFontSize(FONT_SIZE_TABLE_HEAD);
	table.addColumn();
	table.addColumn();
	table.addColumn();
	
	var row1 = table.getBody().addRow();
	var c11 = row1.addCell();
	var c12 = row1.addCell();
	var c13 = row1.addCell();
	c11.addBlock().addExternalGraphic(FILE_PATH + "/logo-left.png").setContentWidth(6.0);
	c13.addBlock().setTextAlign("center").addExternalGraphic(FILE_PATH + "/logo-right.png").setContentWidth(8.0);
	
	var row2 = table.getBody().addRow();
	var c21 = row2.addCell();
	var c22 = row2.addCell();
	var c23 = row2.addCell();
	
	// -------------------------------------------------------------------
	// Left: TO
	// -------------------------------------------------------------------

	c21.setDisplayAlign("center");
	c21.setPaddingLeft("36pt");
	c21.addBlock("Customer").setFontWeight("bold").setFontSize(FONT_SIZE_TITLES).setColor(COLOR_TABLE_HEADER_GREEN);
	c21.addBlock(m_data.m_to.m_company).setFontWeight("bold").setFontSize(FONT_SIZE_TITLES).setSpaceAfter("5pt");
	c21.addBlock(m_data.m_to.m_person);
	c21.addBlock(m_data.m_to.m_address1);
	c21.addBlock(m_data.m_to.m_address2);
	c21.addBlock(m_data.m_to.m_address3);
	
	// -------------------------------------------------------------------
	// Add a SVG barcode
	// -------------------------------------------------------------------
	c22.addBlock().addInstreamForeignObject(new Ax.barcode.SVG("A0383930000").setPrintText(true).setHeight(1.25).toCode128());
	
	// -------------------------------------------------------------------
	// Right: Balance due
	// -------------------------------------------------------------------
	c23.setPadding("20pt");
	c23.setDisplayAlign("center");
	c23.setBorderTopStyle("solid");
	c23.setBorderTopColor(COLOR_LIGHT_GRAY);
	c23.setBorderBottomStyle("solid");
	c23.setBorderBottomColor(COLOR_LIGHT_GRAY);
	c23.addBlock("Balace Due").setFontWeight("bold").setFontSize(FONT_SIZE_TITLES).setColor(COLOR_TABLE_HEADER_GREEN);;
	c23.addBlock(c23.format(m_data.m_invoice.m_balance_due, m_locale, NUMBER_FORMAT)).setFontWeight("bold").setFontSize(FONT_SIZE_TITLES).setSpaceAfter("5pt");
	c23.addBlock(m_data.m_invoice.m_order);
	c23.addBlock(m_data.m_invoice.m_number);
	c23.addBlock(m_data.m_invoice.m_terms);
	c23.addBlock(c23.format(m_data.m_invoice.m_date_invoice, m_locale, "MMM, dd yyyy"));
	// Align all text added to cell (do at end)
	c23.setTextAlign("right");

});

// =======================================================================
// CONFIGURE AFTER
// =======================================================================
template.setAfter(after => {
	var totalPageNumbeId = after.getRoot().getPageSequence().getTotalPageNumberCitation();
	var pagenumber = after
			.addBlock()
			.setFontFamily(FONT_NAME)
			.setFontSize(FONT_SIZE_TABLE_BODY)
			.setTextAlign("end")
			.setPaddingTop(6)
			.setBorderTopColor(COLOR_LINE)
			.setBorderTopStyle("solid");

	pagenumber.addInline()
		.addText("Page ")
		.putPageNumber()
		.addText(" - ")
		.putPageNumberCitation(totalPageNumbeId)
	;
});

// =======================================================================
// CONFIGURE BODY
// =======================================================================
template.setBody(body => {

	var table = body.addTable();
	table.setFontFamily(FONT_NAME);
	table.setFontSize(FONT_SIZE_TABLE_BODY);
	table.setSpaceBefore("20pt");
	table.addColumn("").setColumnWidth(1).setAlign("center");
	table.addColumn("Item & Description").setColumnWidth(8);
	table.addColumn("Qty").setColumnWidth(2.0).setAlign("right");
	table.addColumn("Rate").setColumnWidth(2.0).setAlign("right");
	table.addColumn("Discount").setColumnWidth(2.5).setAlign("right");
	table.addColumn("Ammount").setColumnWidth(3.5).setAlign("right");
	
	// Header row black background
	table.getHeader().getRows().forEach(row => {
		row.setBackgroundColor(COLOR_TABLE_HEADER_GREEN);
	});

	// Header cols white text + padding
	table.getHeader().getColumns().forEach(col => {
		col.getCell().setFontSize(FONT_SIZE_TABLE_HEAD);
		col.getCell().setColor("#FFFFFF");
		col.getCell().setFontWeight("bold");
		col.getCell().setBackgroundColor(COLOR_TABLE_HEADER_GREEN);
		col.getCell().setPaddingLeft(8);
		col.getCell().setPaddingRight(8);
		col.getCell().setPaddingTop(6);
		col.getCell().setPaddingBottom(6);
	});

	for (var tuple of m_resultset) {
		var row = table.getBody().addRow(
			null,
			tuple.get("DESCRIPTION"),
			table.format(tuple.get("QTY"), m_locale, NUMBER_FORMAT),
			table.format(tuple.get("RATE"), m_locale, NUMBER_FORMAT),
			tuple.get("UNIT"),
			table.format(tuple.get("SUBTOTAL"), m_locale, NUMBER_FORMAT)
		);
		row.getCell(1).getBlock().setFontWeight("bold");
		row.getCell(1).addBlock(tuple.get("TEXT")).setColor(COLOR_LIGHT_GRAY).setKeepWithPrevious("always");
		row.forEach(cell => {
			cell.setDisplayAlign("center");
			cell.setPaddingLeft(8);
			cell.setPaddingRight(8);
			cell.setPaddingTop(8);
			cell.setPaddingBottom(8);
			if (cell.getColumnIndex() < 2) {
				cell.setBorderBottomStyle("solid");
				cell.setBorderBottomColor("black");
			}
		});
		row.setBorderBottomStyle("solid");
		row.setBorderBottomColor(COLOR_LINE);
	}

	table.getBody().getLastRow().forEach(cell => {
		cell.setBorderBottomStyle("solid");
		cell.setBorderBottomColor("black");
	});
	var row = table.getBody().addRow();
	//row.setKeepWithPreviousWithinPage("always");
	row.setBackgroundColor(COLOR_TABLE_FOOTER_BLUE);
	row.addCell();
	row.addCell().setPaddingLeft(8).addBlock("DUE by " + row.format(m_data.m_invoice.m_date_due, m_locale, DATE_FORMAT)).setFontSize(12);
	row.addCell().setColspan(4).addBlock("$ " + row.format(m_data.m_invoice.m_balance_due, m_locale, NUMBER_FORMAT)).setFontSize(16).setTextAlign("right");
	row.forEach(cell => {
		cell.setColor("#FFFFFF");
		cell.setBackgroundColor(COLOR_TABLE_FOOTER_BLUE);
		cell.setDisplayAlign("center");
		cell.setPaddingLeft(8);
		cell.setPaddingRight(8);
		cell.setPaddingTop(8);
		cell.setPaddingBottom(8);
	});

});

// =======================================================================
// CONFIGURE BODY FOOTNOTE
// =======================================================================
template.setBodyFootNote(footnote => {
	var table = footnote.getFootNoteBody().addTable();
	table.addColumn().setColumnWidth(8.0);
	table.addColumn();
	var row = table.getBody().addRow();

	__addLeftFootNote(row.addCell());
	__addRightFootNote(row.addCell());

});

function __addLeftFootNote(cell)
{
	var left = cell.addTable();
	left.setFontFamily(FONT_NAME);
	left.setFontSize(FONT_SIZE_TABLE_BODY);
	left.addColumn().setColumnWidth(1.5).setAlign("center");
	left.addColumn();
	
	var data = [
		[ "icon-phone.png", m_data.m_from.m_phone ],
		[ "icon-mail.png", m_data.m_from.m_email ],
		[ "icon-location.png", m_data.m_from.m_address1 + "\n" + m_data.m_from.m_address2 + "\n" + m_data.m_from.m_address3 ],
	];
	
	for (var temp of data) {
		var row = left.getBody().addRow();
		row.addCell().addBlock().addExternalGraphic(FILE_PATH + "/" + temp[0]).setContentWidth(1.0);
		row.addCell().setDisplayAlign("center").addBlock(temp[1]).setLinefeedTreatment("preserve");
	}	
}

function __addRightFootNote(cell)
{
	var right = cell.addTable();
	right.setFontFamily(FONT_NAME);
	right.setFontSize(FONT_SIZE_TABLE_HEAD);
	right.addColumn().setColumnWidth(1.8);
	right.addColumn();
	right.addColumn().setColumnWidth(1.2);
	right.addColumn();
	
	var row1 = right.getBody().addRow();
	row1.setHeight("20pt");
	row1.addCell().setNumberOfColumnsSpanned(4).addBlock("PAYMENT METHOD").setFontSize(12).setFontWeight("bold");

	var row2 = right.getBody().addRow();
	row2.setHeight("14pt");
	row2.addCell().addBlock("Account No");
	row2.addCell().addBlock(": 123 456 890");
	row2.addCell().addBlock("PayPal");
	row2.addCell().addBlock(": payments@fantasy.com");

	var row3 = right.getBody().addRow();
	row3.setHeight("14pt");
	row3.addCell().addBlock("BANK");
	row3.addCell().addBlock(": BANK0000123456789");
	row3.addCell().addBlock("SWIFT");
	row3.addCell().addBlock(": 12345678");

	var row4 = right.getBody().addRow();
	row4.setHeight("20pt");
	row4.addCell().setNumberOfColumnsSpanned(4)
		.addBlock()
		.addExternalGraphic(FILE_PATH + "/logo-signature.png")
		.setContentWidth(6.0);
}


// ====================================================================
// GENERATE PDF
// ====================================================================

var fop = template.toFOP();
let pdf = new Ax.fop.Processor().transform(fop);
//new Ax.io.File("/tmp/InvoiceStyle1Script.fop").write(fop);
//new Ax.io.File("/tmp/InvoiceStyle1Script.pdf").write(pdf);
return pdf;

</script>
Click here to download the PDF example

6.2 Invoice 2 example

Same as before with style variations

Copy

Example

<script>
    function print_invoice(obj_invoice,obj_lines) {
    var FILE_PATH = "https://bitbucket.org/deister/axional-docs-resources/raw/master/FOP/Invoices/Style1";
    
    var SVG_WATERMARK =
        "<svg:svg width='600' height='300' xmlns:svg='http://www.w3.org/2000/svg'>\n"+
        "  <svg:g transform='rotate(-30)'>\n"+
        "    <svg:text x='0' y='300' style='font-family:Courier;font-size:140;font-weight:normal;stroke-width:0.5;fill:#EDEDED;stroke:lightgray;stroke-opacity:0.75;'>\n"+
        "        COPY\n"+
        "    </svg:text>\n"+
        "  </svg:g>\n"+
        "</svg:svg>\n";
    var template = new Ax.fop.SinglePageTemplate("A4");
    
    
    // =======================================================================
    // COLORS
    // =======================================================================
    var COLOR_LIGHT_GRAY = "#757575";
    var COLOR_LIGHT_BLUE = "#03A9F4";
    var COLOR_BLUE  = "#0288D1";
    var COLOR_LINE = "#a2a0a7";
    var COLOR_WHITE = "#fff";
    var COLOR_BLACK = "#000";

    // =======================================================================
    // FORMATS
    // =======================================================================

    var m_locale = "us";
    var NUMBER_FORMAT = "%,.2f";
    var DATE_FORMAT = "MMM, dd, yyyy";
    
    // =======================================================================
    // FONTS
    // =======================================================================
    var FONT_NAME = "Noto Sans";
    var	FONT_SIZE_TITLE = 25;
    var FONT_SIZE_NAME = 15;
    var	FONT_SIZE_PRIMARY = 10;
    var	FONT_SIZE_SECUNDARY = 8;
    
    // =======================================================================
    // CONFIGURE FOP ROOT LAYOUT
    // =======================================================================
    
    template.setRoot(root => {
        //root.setDebug("*"); // Used to see how much each space occupies on the PDF
        root.getSimplePageMaster().getRegionBefore().setExtent(8.5);
        root.getSimplePageMaster().getRegionAfter().setExtent(9.0);
        root.getSimplePageMaster().getRegionStart().setExtent(1.0);
        root.getSimplePageMaster().getRegionEnd().setExtent(1.0);
        root.getSimplePageMaster().setMargins(0, 0, 0, 0);
    });

    // =======================================================================
	// CONFIGURE START
	// =======================================================================

	template.setStart(start => {
		start.addBlock().setPaddingTop("10pt").setFontFamily(FONT_NAME).setFontSize(8).setTextAlign("center")
			.addTextLiteral("&#x00A9; 2020 deister software");

	});

	// =======================================================================
	// CONFIGURE END
	// =======================================================================
	template.setEnd(end => {
		end.addBlock().setPaddingTop("10pt").setFontFamily(FONT_NAME).setFontSize(8).setTextAlign("center")
			.addTextLiteral("&#x00A9; 2020 deister software");

	});
	
    // =======================================================================
	// CONFIGURE BEFORE
	// =======================================================================
	template.setBefore(before => {
	      
	  	before.addBlockContainer()
	  		.setPosition("absolute")
	  		.setTop("12.5cm")
	  		.setLeft("0.0cm")
	  		.addBlock()

	  	var table = before.addTable();
	  	table.setFontFamily(FONT_NAME);
	  	table.setFontSize(FONT_SIZE_SECUNDARY);
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();

	  	var row1 = table.getBody().addRow();
	  	row1.setPadding("5pt")
	  	var c11 = row1.addCell().setColspan(3);
	  	var c12 = row1.addCell().setLineHeight(12.0).setColspan(3);

	  	c11.addBlock().addExternalGraphic(FILE_PATH + "/logo-right.png").setContentWidth(6.0);//Add the company logo
	  	c11.setPaddingTop("40pt");
	  	c11.setPaddingLeft("36pt");
	  	c12.setPaddingLeft("20pt");
	  	c12.addBlock("INVOICE").setFontSize(FONT_SIZE_TITLE).setColor(COLOR_LIGHT_BLUE).setLineHeight(35.0);//details of the invoice
	  	c12.addBlock("Invoice No.#"+obj_invoice.id).setFontSize(FONT_SIZE_PRIMARY).setSpaceAfter("5pt");
	  	c12.addBlock("Invoice date"	+"	"+":"+c12.format(obj_invoice.date,m_locale,DATE_FORMAT));
	  	c12.addBlock("Issue date"	+"		"+":"+c12.format(obj_invoice.issue_date,m_locale,DATE_FORMAT));
	  	c12.addBlock("Account No."	+"	"+":"+obj_invoice.account_num);
	  	c12.setPaddingTop("40pt");

	  	var row2 = table.getBody().addRow();
	  	var c21 = row2.addCell().setLineHeight(12.0).setColspan(3);//the separation between lines can be adjusted by setlineheight
	  	var c22 = row2.addCell().setLineHeight(12.0).setColspan(3);

	  	c21.setDisplayAlign("center");
	  	c21.setPaddingLeft("36pt");
	  	c21.addBlock("To");
	  	c21.addBlock(obj_invoice.client_name).setFontSize(FONT_SIZE_NAME).setSpaceBefore("5pt").setSpaceAfter("5pt");//Details of the client
	  	c21.addBlock("Director").setSpaceAfter("5pt");
	  	c21.addBlock("Address: "+obj_invoice.client_address);
	  	c21.addBlock("E-mail: "+obj_invoice.client_mail);
	  	c21.addBlock("Phone number: "+obj_invoice.client_phone);

	  	c22.setPadding("20pt");
	  	c22.setDisplayAlign("center");
	  	c22.addBlock("Payment Method: ").setFontWeight("bold").setSpaceAfter("5pt");
	  	c22.addBlock("Paypal: "+obj_invoice.paypal).setColor(COLOR_LIGHT_GRAY);
	  	c22.addBlock("Card payment we accept: "+obj_invoice.accepted_cards).setColor(COLOR_LIGHT_GRAY);
	  	// Align all text added to the cell 
	  	c22.setTextAlign("left");

	  	var row3 = table.getBody().addRow();

	  	row3.setBackgroundColor(COLOR_BLUE);
	  	row3.setPadding("15pt")
	  	var c31 =row3.addCell().setLineHeight(12.0);
	  	var c32 =row3.addCell().setColspan(2).setLineHeight(12.0);
	  	var c33 =row3.addCell().setLineHeight(12.0);
	  	var c34 =row3.addCell().setLineHeight(12.0);
	  	var c35 =row3.addCell().setLineHeight(12.0);
	  	//The first row contains the column descriptions, and must be inserted into the before region
	  	c31.addBlock("SL").setColor(COLOR_WHITE).setTextAlign("center").setPaddingTop("5pt").setPaddingBottom("5pt");
	  	c32.addBlock("ITEM DESCRIPTIONS").setColor(COLOR_WHITE).setTextAlign("center").setPaddingTop("5pt").setPaddingBottom("5pt");
	  	c33.addBlock("RATE").setColor(COLOR_WHITE).setTextAlign("center").setBackgroundColor(COLOR_BLACK).setPaddingTop("5pt").setPaddingBottom("5pt");
	  	c34.addBlock("QTY").setColor(COLOR_WHITE).setTextAlign("center").setBackgroundColor(COLOR_BLACK).setPaddingTop("5pt").setPaddingBottom("5pt");
	  	c35.addBlock("PRICE").setColor(COLOR_WHITE).setTextAlign("center").setBackgroundColor(COLOR_BLACK).setPaddingTop("5pt").setPaddingBottom("5pt");

	  });

    // =======================================================================
    // SET AFTER REGION CONTENT
    // =======================================================================
    template.setAfter(after => {
		var table = after.addTable();
        table.addColumn();

	  	var row1 = table.getBody().addRow();
	  	var row2 = table.getBody().addRow();

	  	var cell1 = row1.addCell();
        //We add table inside cells to have better control of the elements position
	  	var table1 = cell1.addTable().setPageBreakInside("avoid");//In order to prevent a block appearing between 2 pages, we add .setPageBreakInside()
        table1.setFontSize(FONT_SIZE_PRIMARY);
        table1.addColumn();
        table1.addColumn().setColumnWidth(8.0);

        var row1 = table1.getBody().addRow();

        var c11 = row1.addCell().setLineHeight(12.0);
        var c12 = row1.addCell().setLineHeight(12.0);

        var t2 = c12.addTable();
        t2.addColumn();
        t2.addColumn();

        rowt1 = t2.getBody().addRow().setHeight(0.5);
        rowt2 = t2.getBody().addRow().setHeight(0.5);
        rowt3 = t2.getBody().addRow();
        rowt4 = t2.getBody().addRow();

        ct11 = rowt1.addCell().setLineHeight(12.0);
        ct12 = rowt1.addCell().setLineHeight(12.0);
        ct21 = rowt2.addCell().setDisplayAlign("center").setLineHeight(12.0);
        ct22 = rowt2.addCell().setDisplayAlign("center").setLineHeight(12.0);
        ct3  = rowt3.addCell().setColspan(2).setRowspan(1).setLineHeight(12.0);

        c11.addBlock("Terms & Conditions:").setPageBreakInside("avoid");
        c11.addBlock(LOREM).setFontSize(FONT_SIZE_SECUNDARY).setColor(COLOR_LIGHT_GRAY).setTextAlign("justified");
        c11.setPaddingTop("50pt");


        ct11.setPadding("20pt");
		ct11.addBlock("Sub-Total").setColor(COLOR_LIGHT_GRAY).setPaddingLeft("14pt");
		ct11.addBlock("Tax: Vat ("+obj_invoice.taxvalue+"%)").setColor(COLOR_LIGHT_GRAY).setPaddingLeft("14pt");
		
		ct12.setPadding("20pt");
		ct12.addBlock(ct12.format(obj_invoice.subtotal,m_locale,NUMBER_FORMAT)+" €").setColor(COLOR_LIGHT_GRAY).setTextAlign("right").setPaddingLeft("5pt");
		ct12.addBlock(ct12.format(obj_invoice.tax,m_locale,NUMBER_FORMAT)+" €").setColor(COLOR_LIGHT_GRAY).setTextAlign("right").setPaddingLeft("5pt");

		//We can define blocks as variables to separate its properties among multiple lines
		cbt21 = ct21.addBlock("Grand Total:").setColor(COLOR_WHITE).setFontWeight("bold").setBackgroundColor(COLOR_BLUE)
		cbt21.setPaddingTop("5pt").setPaddingBottom("5pt").setPaddingLeft("20pt").setStartIndent("15pt");
		ct21.setPadding("5pt")

		ct22.setPadding("5pt")
		cbt22 = ct22.addBlock(ct22.format(obj_invoice.total,m_locale,NUMBER_FORMAT)+" €").setColor(COLOR_WHITE).setFontWeight("bold").setBackgroundColor(COLOR_LIGHT_BLUE)
		cbt22.setTextAlign("right").setPaddingTop("5pt").setPaddingBottom("5pt").setEndIndent("15pt")
		cbt22.setPaddingRight("20pt");

		ct3.addBlock("Robert Smith").setTextAlign("center")
		ct3.addBlock("Web Designer").setTextAlign("center").setFontSize(FONT_SIZE_SECUNDARY).setColor(COLOR_LIGHT_GRAY)

		cell2 = row2.addCell();
		var table2 = cell2.addTable().setPageBreakInside("avoid");
		table2.addColumn();
		table2.addColumn();
		table2.addColumn();
		var row21 = table2.getBody().addRow();
		var row22 = table2.getBody().addRow();

		var c211 = row21.addCell().setPadding("15pt").setLineHeight(12.0);
		var c212 = row21.addCell().setPadding("15pt").setLineHeight(12.0);
		var c213 = row21.addCell().setPadding("15pt").setLineHeight(12.0);
		var c22  = row22.addCell().setColspan(3).setLineHeight(12.0);

		var t21 = c211.addTable();
		t21.addColumn().setColumnWidth(1.8);
		t21.addColumn();
		t21.setFontSize(FONT_SIZE_SECUNDARY).setColor(COLOR_LIGHT_GRAY);
		t21.setBorderStyle("solid").setBorderColor(COLOR_LIGHT_BLUE)
		var row211 = t21.getBody().addRow();
		var row212 = t21.getBody().addRow();

		var ct2111 = row211.addCell().setRowspan(2);
		var ct2112 = row211.addCell();
		var ct2122 = row212.addCell();

		cbt2111 = ct2111.addBlock().setStartIndent("15pt");
		cbt2111.addExternalGraphic(FILE_PATH + '/'+"icon-phone.png").setContentWidth(1.0);
		cbt2111.setSpaceBefore("5pt").setSpaceAfter("5pt").setPaddingBottom("5pt");
		cbt2112 = ct2112.addBlock(obj_invoice.company_phone).setLinefeedTreatment("preserve").setSpaceBefore("10pt");
		cbt2122 = ct2122.addBlock(obj_invoice.company_phone).setLinefeedTreatment("preserve");
		c211.setTextAlign("center");

		var t22 = c212.addTable();
		t22.addColumn().setColumnWidth(1.8);
		t22.addColumn();
		t22.setFontSize(FONT_SIZE_SECUNDARY).setColor(COLOR_LIGHT_GRAY);
		t22.setBorderStyle("solid").setBorderColor(COLOR_LIGHT_BLUE)
		var row221 = t22.getBody().addRow();
		var row222 = t22.getBody().addRow();

		var ct2211 = row221.addCell().setRowspan(2);
		var ct2212 = row221.addCell();
		var ct2222 = row222.addCell();

		cbt2211 = ct2211.addBlock().setStartIndent("15pt");
		cbt2211.addExternalGraphic(FILE_PATH + '/'+"icon-mail.png").setContentWidth(1.0);
		cbt2211.setSpaceBefore("5pt").setSpaceAfter("5pt").setPaddingBottom("5pt");
		cbt2212 = ct2212.addBlock(obj_invoice.company_mail).setLinefeedTreatment("preserve").setSpaceBefore("10pt");
		cbt2222 = ct2222.addBlock(obj_invoice.company_web).setLinefeedTreatment("preserve");
		c212.setTextAlign("center");
		
		var t23 = c213.addTable();
		t23.addColumn().setColumnWidth(1.8);
		t23.addColumn();
		t23.setFontSize(FONT_SIZE_SECUNDARY).setColor(COLOR_LIGHT_GRAY);
		t23.setBorderStyle("solid").setBorderColor(COLOR_LIGHT_BLUE)
		var row231 = t23.getBody().addRow();
		var row232 = t23.getBody().addRow();

		var ct2311 = row231.addCell().setRowspan(2);
		var ct2312 = row231.addCell();
		var ct2322 = row232.addCell();

		cbt2311 = ct2311.addBlock().setStartIndent("15pt");
		cbt2311.addExternalGraphic(FILE_PATH + '/'+"icon-location.png").setContentWidth(1.0);
		cbt2311.setSpaceBefore("5pt").setSpaceAfter("5pt").setPaddingBottom("5pt").setPageBreakInside("avoid");
		cbt2312 = ct2312.addBlock(obj_invoice.company_address).setLinefeedTreatment("preserve").setSpaceBefore("10pt");
		cbt2322 = ct2322.addBlock("").setLinefeedTreatment("preserve");
		c213.setTextAlign("center");

		c22.addBlock(LOREM).setColor(COLOR_LIGHT_GRAY).setSpaceBefore("10pt");


	});
    
    // =======================================================================
    // SET BODY FLOW CONTENT
    // =======================================================================
    template.setBody(body => {
    	
        var table = body.addTable();
    	table.setFontFamily(FONT_NAME);
        table.setFontSize(FONT_SIZE_PRIMARY);
        table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();

	  	var row1 = table.getBody().addRow();
	  	

	  	var counter = 1;//counter is used to obtain the row number
	  	for (var i of obj_lines) {
	  		var row = table.getBody().addRow();
	  		var c1 = row.addCell().setLineHeight(12.0);
	  		var c2 = row.addCell().setColspan(2).setLineHeight(12.0);
	  		var c3 = row.addCell().setLineHeight(12.0);
	  		var c4 = row.addCell().setLineHeight(12.0);
	  		var c5 = row.addCell().setLineHeight(12.0);
	  		c1.addBlock(counter).setTextAlign("center").setSpaceBefore("14pt");
	  		c1.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c1.setBorderRightStyle("solid").setBorderRightColor(COLOR_LINE);
	  		c1.setPadding("10pt").setDisplayAlign("after");
	  		c2.addBlock(i.ITEM_NAME).setFontWeight("bold");
	  		c2.addBlock(i.DESCRIPTION).setPageBreakInside("avoid").setFontSize(FONT_SIZE_SECUNDARY);
	  		c2.setTextAlign("justified").setPadding("10pt");
	  		c2.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c2.setBorderRightStyle("solid").setBorderRightColor(COLOR_LINE);
	  		c3.addBlock(c3.format(i.RATE,m_locale,NUMBER_FORMAT)+" €").setTextAlign("center").setSpaceBefore("14pt");
	  		c3.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c3.setBorderRightStyle("solid").setBorderRightColor(COLOR_LINE);
	  		c3.setPadding("10pt").setDisplayAlign("after");
	  		c4.addBlock(i.QTY).setTextAlign("center").setSpaceBefore("14pt");
	  		c4.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c4.setBorderRightStyle("solid").setBorderRightColor(COLOR_LINE);
	  		c4.setPadding("10pt").setDisplayAlign("after");
	  		var PRICE = i.RATE*i.QTY;//The price is calculated as the product between the rate and the quantity
	  		c5.addBlock(c5.format(PRICE,m_locale,NUMBER_FORMAT)+" €").setTextAlign("center").setSpaceBefore("14pt").setPageBreakInside("avoid");
	  		c5.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c5.setPadding("10pt").setDisplayAlign("after");
	  		counter = counter+1;
	  		}
	  	
		
    });

	// =======================================================================
	// CONFIGURE BODY FOOTNOTE
	// =======================================================================
	template.setBodyFootNote(footnote => {
		

	});


  // ====================================================================
  // GENERATE PDF
  // ====================================================================

  var fop = template.toFOP();
  let pdf = new Ax.fop.Processor().transform(fop);
  return pdf;
}
    </script>
// *****************************************************************************
// * DATA
// *****************************************************************************
// Needed data
var temp_invoice = {
	"id"				: 2342343,
	"date"				: new Ax.sql.Date("2020-02-19"),
	"issue_date"		: new Ax.sql.Date("2020-02-19"),
	"account_num"		: 2342323423,
	"client_name"		: "John Smith",
	"client_address"	: "Avenida Europa Edificio Alcor Plaza 2-2",
	"client_mail"		: "JohnSmith@email.com",
	"client_phone"		: "918386100",
	"paypal"			: "paypaladdress@paypal.es",
	"accepted_cards"	: "Visa",
	"company_phone"		: "345345343",
	"company_mail"		: "company@mail.com",
	"company_web"		: "www.company.com",
	"company_address"	: "old street 123",
    "taxvalue"          : 15,
    "subtotal"          : 3300,
    "tax"               : 495,
    "total"             : 3795
}

var LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
//Needed data for the invoice lines, note we use a resultset
var m_resultset = new Ax.rs.Reader().build(
    	[
			[ "Web Design", LOREM, 15, 10],
			[ "Graphic Design", LOREM, 29, 50],
			[ "Brand Identity", LOREM, 35, 10],
			[ "Magazine Design", LOREM, 11, 50],
			[ "Flyer Design", LOREM, 10, 20],
			[ "Flyer Design", LOREM, 10, 20],
			[ "Flyer Design", LOREM, 10, 20],
			[ "Flyer Design", LOREM, 10, 20],
    	], 
    	options => {
	        options.setColumnNames(
	        	[
					"ITEM_NAME",
					"DESCRIPTION",
					"RATE",
					"QTY"
		 		]
		    );
    	}
    );

// ------------------------------------------------------------------------
// OBTAIN PDF
// ------------------------------------------------------------------------

return print_invoice(temp_invoice,m_resultset);
Click here to download the PDF example

6.3 Invoice 3 example

Same as before with style variations

Copy

Example

<script>
function print_invoice(obj_invoice,obj_lines) {
    var FILE_PATH = "https://bitbucket.org/deister/axional-docs-resources/raw/master/FOP/Invoices/Style1";
    
    var SVG_WATERMARK =
        "<svg:svg width='600' height='300' xmlns:svg='http://www.w3.org/2000/svg'>\n"+
        "  <svg:g transform='rotate(-30)'>\n"+
        "    <svg:text x='0' y='300' style='font-family:Courier;font-size:140;font-weight:normal;stroke-width:0.5;fill:#EDEDED;stroke:lightgray;stroke-opacity:0.75;'>\n"+
        "        COPY\n"+
        "    </svg:text>\n"+
        "  </svg:g>\n"+
        "</svg:svg>\n";
    var template = new Ax.fop.SinglePageTemplate("A4");
    
    
    // =======================================================================
    // COLORS
    // =======================================================================
    var COLOR_LIGHT_GRAY = "#e1e1e1";
    var COLOR_LIGHT_BLUE = "#03A9F4";
    var COLOR_DARK_BLUE  = "#252c3b";
    var COLOR_GOLD = "#b5a789";
    var COLOR_LINE = "#a2a0a7";
    var COLOR_WHITE = "#fff";
    var COLOR_BLACK = "#000";
    var COLOR_RED_WINE = "#ac354b";
    var COLOR_GRAY = "#939294";

    // =======================================================================
    // FORMATS
    // =======================================================================

    var m_locale = "us";
    var NUMBER_FORMAT = "%,.2f";
    var DATE_FORMAT = "MMM, dd, yyyy";
    
    // =======================================================================
    // FONTS
    // =======================================================================
    var FONT_NAME = "Noto Sans";
    var	FONT_SIZE_TITLE = 25;
    var FONT_SIZE_NAME = 12;
    var	FONT_SIZE_PRIMARY = 10;
    var	FONT_SIZE_SECUNDARY = 8;
    
    // =======================================================================
    // CONFIGURE FOP ROOT LAYOUT
    // =======================================================================
    
    template.setRoot(root => {
        //root.setDebug("*"); // Used to see how much each space occupies on the PDF
        root.getSimplePageMaster().getRegionBefore().setExtent(10.0);
        root.getSimplePageMaster().getRegionAfter().setExtent(8.25);
        root.getSimplePageMaster().getRegionStart().setExtent(2.0);
        root.getSimplePageMaster().getRegionEnd().setExtent(1.0);
        root.getSimplePageMaster().setMargins(0, 0, 0, 0);
    });

    // =======================================================================
	// CONFIGURE START
	// =======================================================================

	template.setStart(start => {
		var table = start.addTable();//Using a table, we can modify the color of the margins of the page
		table.addColumn();
		table.addColumn().setColumnWidth(4.6);

		var row1 = table.getBody().addRow();
		var row2 = table.getBody().addRow();

		c1 = row1.addCell().setBackgroundColor(COLOR_LIGHT_GRAY);
		c2 = row1.addCell().setBackgroundColor(COLOR_GOLD);
		c3 = row2.addCell();
		c4 = row2.addCell().setBackgroundColor(COLOR_DARK_BLUE);

		c1.addBlock("a").setPaddingBottom("15pt").setColor(COLOR_LIGHT_GRAY);
		c2.addBlock("a").setPaddingBottom("15pt").setColor(COLOR_GOLD);
		c3.addBlock("a").setColor(COLOR_WHITE);
		c4.addBlock("a").setPaddingBottom("15pt").setColor(COLOR_DARK_BLUE);
	});
	
	// =======================================================================
	// CONFIGURE END
	// =======================================================================

	template.setEnd(end => {
		var table = end.addTable();
		table.addColumn().setBackgroundColor(COLOR_DARK_BLUE).setColumnWidth(4.6);
		table.addColumn();

		var row1 = table.getBody().addRow();

		c1 = row1.addCell();
		c2 = row1.addCell();

		c1.addBlock().addTextLiteral("a").setPaddingBottom("15pt").setColor(COLOR_DARK_BLUE);
		c2.addBlock().addTextLiteral("a").setPaddingBottom("15pt").setColor(COLOR_WHITE);
	});
	
    // =======================================================================
	// CONFIGURE BEFORE
	// =======================================================================
	template.setBefore(before => {
	      
	  	before.addBlockContainer()
	  		.setPosition("absolute")
	  		.setTop("12.5cm")
	  		.setLeft("0.0cm")
	  		.addBlock()

	  	var table = before.addTable();
	  	table.setFontFamily(FONT_NAME);
	  	table.setFontSize(FONT_SIZE_SECUNDARY);
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();

	  	var row1 = table.getBody().addRow();
	  	row1.setPadding("5pt").setBackgroundColor(COLOR_DARK_BLUE);
	  	var c11 = row1.addCell().setColspan(3);
	  	var c12 = row1.addCell().setLineHeight(12.0).setColspan(3);
		c12.setTextAlign("center");

	  	var t2 = c12.addTable().setBorderLeftStyle("solid").setBorderLeftColor(COLOR_GOLD)
	  	t2.addColumn().setColumnWidth(1.5);
	  	t2.addColumn();

	  	var rowt21 = t2.getBody().addRow();
	  	var rowt22 = t2.getBody().addRow();
	  	var rowt23 = t2.getBody().addRow();

	  	var ct21 = rowt21.addCell().setColspan(2);
	  	var ct221 = rowt22.addCell();
	  	var ct222 = rowt22.addCell();
	  	var ct231 = rowt23.addCell();
	  	var ct232 = rowt23.addCell();

	  	ct21.addBlock(obj_invoice.company_address).setColor(COLOR_WHITE).setFontWeight("bold").setSpaceBefore("20pt").setStartIndent("20pt");
	  	cbt221 = ct221.addBlock().setStartIndent("15pt").setEndIndent("40pt");
		cbt221.addExternalGraphic(FILE_PATH + '/'+"icon-phone.png").setContentWidth(0.5);
		cbt221.setSpaceBefore("5pt").setSpaceAfter("5pt").setPaddingBottom("5pt");
		cbt222 = ct222.addBlock(obj_invoice.company_phone).setLinefeedTreatment("preserve").setSpaceBefore("9pt").setColor(COLOR_WHITE);
		cbt231 = ct231.addBlock().setStartIndent("15pt").setEndIndent("40pt");
		cbt231.addExternalGraphic(FILE_PATH + '/'+"icon-mail.png").setContentWidth(0.5);
		cbt231.setSpaceBefore("5pt").setSpaceAfter("5pt").setPaddingBottom("5pt");
		cbt232 = ct232.addBlock(obj_invoice.company_mail).setLinefeedTreatment("preserve").setSpaceBefore("3pt").setColor(COLOR_WHITE);
		cbt232 = ct232.addBlock(obj_invoice.company_web).setLinefeedTreatment("preserve").setColor(COLOR_WHITE);

	  	c11.addBlock().addExternalGraphic(FILE_PATH + "/logo-right.png").setContentWidth(6.0);//Add the company logo
	  	c11.setPaddingTop("20pt").setPaddingBottom("20pt");
	  	

	  	var row2 = table.getBody().addRow();
	  	var c21 = row2.addCell().setLineHeight(12.0).setColspan(3);//the separation between lines can be adjusted by setlineheight
	  	var c22 = row2.addCell().setLineHeight(12.0).setColspan(3);

	  	cb21 = c21.addBlock().setSpaceAfter("5pt").setSpaceBefore("20pt").addInline().addText("Bill To: ").setFontWeight("bold").setColor(COLOR_GOLD).setFontSize(FONT_SIZE_PRIMARY).addInline().addText(obj_invoice.client_name).setFontWeight("normal").setColor(COLOR_BLACK)
	  	cb21.setFontSize(FONT_SIZE_PRIMARY);//With addInline(), we can apply different format to different parts of the text
        c21.addBlock("Account manager").setSpaceAfter("5pt");
	  	c21.addBlock().addInline().addText("A: ").setFontWeight("bold").addInline().addText(obj_invoice.client_address).setFontWeight("normal");
	  	c21.addBlock().addInline().addText("W: ").setFontWeight("bold").addInline().addText(obj_invoice.client_mail).setFontWeight("normal");
	  	c21.addBlock().addInline().addText("P: ").setFontWeight("bold").addInline().addText(obj_invoice.client_phone).setFontWeight("normal");

	  	var t4 = c22.addTable()
	  	t4.addColumn();
	  	t4.addColumn();
	  	t4.addColumn();

	  	var rowt41 = t4.getBody().addRow();
	  	var rowt42 = t4.getBody().addRow();

	  	var ct41 = rowt41.addCell().setColspan(3);
	  	var ct421 = rowt42.addCell().setPaddingTop("10pt").setPaddingBottom("10pt");
	  	var ct422 = rowt42.addCell().setPaddingTop("10pt").setPaddingBottom("10pt");
	  	var ct423 = rowt42.addCell().setPaddingTop("10pt").setPaddingBottom("10pt");

	  	c22.setPaddingLeft("20pt");
	  	ct41.addBlock("INVOICE").setFontSize(FONT_SIZE_TITLE).setLineHeight(35.0).setBorderBottomStyle("solid").setSpaceAfter("20pt");//details of the invoice
	  	ct421.addBlock("A/C No:").setBorderRightStyle("solid");
	  	ct421.addBlock(`#${obj_invoice.account_num}`).setBorderRightStyle("solid");
	  	ct422.addBlock("Invoice date:").setBorderRightStyle("solid").setStartIndent("15pt");
	  	ct422.addBlock(ct422.format(obj_invoice.date,m_locale,DATE_FORMAT)).setBorderRightStyle("solid").setStartIndent("15pt");
	  	ct423.addBlock("Issue date").setStartIndent("15pt");
	  	ct423.addBlock(ct423.format(obj_invoice.issue_date,m_locale,DATE_FORMAT)).setStartIndent("15pt");
	  	c22.setPaddingTop("40pt");

	  	var row3 = table.getBody().addRow();

	  	row3.setPadding("15pt")
	  	row3.setBorderTopStyle("solid").setBorderBottomStyle("solid");
	  	var c31 =row3.addCell().setLineHeight(12.0);
	  	var c32 =row3.addCell().setColspan(2).setLineHeight(12.0);
	  	var c33 =row3.addCell().setLineHeight(12.0);
	  	var c34 =row3.addCell().setLineHeight(12.0);
	  	var c35 =row3.addCell().setLineHeight(12.0);
	  	//The first row contains the column descriptions, and we must insert it into the before region
	  	c31.addBlock("D. DATE").setTextAlign("center").setPaddingTop("10pt").setPaddingBottom("10pt").setFontSize(FONT_SIZE_NAME);
	  	c32.addBlock("ITEM DESCRIPTION").setTextAlign("center").setPaddingTop("10pt").setPaddingBottom("10pt").setFontSize(FONT_SIZE_NAME);
	  	c33.addBlock("UNITY PRICE").setTextAlign("center").setPaddingTop("10pt").setPaddingBottom("10pt").setFontSize(FONT_SIZE_NAME);
	  	c34.addBlock("QTY").setTextAlign("center").setPaddingTop("10pt").setPaddingBottom("10pt").setFontSize(FONT_SIZE_NAME);
	  	c35.addBlock("TOTAL").setTextAlign("center").setPaddingTop("10pt").setPaddingBottom("10pt").setFontSize(FONT_SIZE_NAME);

	  });

    // =======================================================================
    // SET AFTER REGION CONTENT
    // =======================================================================
    template.setAfter(after => {
		var table = after.addTable();
		table.addColumn();

		var row1 = table.getBody().addRow();
		var row2 = table.getBody().addRow();

		var cell1 = row1.addCell();
		var cell2 = row2.addCell();
	  	
		var table1 = cell1.addTable().setPageBreakInside("avoid");//In order to prevent a block appearing between 2 pages, we add .setPageBreakInside()
        table1.setFontSize(FONT_SIZE_PRIMARY);
        table1.addColumn();
        table1.addColumn().setColumnWidth(8.0);
        table1.setBorderTopStyle("solid");

        var row11 = table1.getBody().addRow();

        var c111 = row11.addCell().setLineHeight(12.0);
        var c112 = row11.addCell().setLineHeight(12.0);

        var t12 = c112.addTable();
        t12.addColumn();
        t12.addColumn();

        rowt11 = t12.getBody().addRow().setHeight(0.5);
        rowt12 = t12.getBody().addRow().setHeight(0.5);
        rowt13 = t12.getBody().addRow();

        ct111 = rowt11.addCell().setLineHeight(15.0);
        ct112 = rowt11.addCell().setLineHeight(15.0);
        ct121 = rowt12.addCell().setDisplayAlign("center").setLineHeight(12.0);
        ct122 = rowt12.addCell().setDisplayAlign("center").setLineHeight(12.0);

        c111.addBlock("PAYMENT METHOD").setPageBreakInside("avoid").setColor(COLOR_GOLD).setBorderBottomStyle("solid").setBorderBottomColor(COLOR_GRAY).setEndIndent("120pt").setSpaceAfter("5pt");
        cb111 = c111.addBlock().setTextAlign("justified").addInline().addText("Paypal: ").setFontWeight("bold").setFontSize(FONT_SIZE_SECUNDARY).setSpaceAfter("5pt")
        cb111.addInline().addText(obj_invoice.paypal).setColor(COLOR_GRAY).setFontWeight("normal");
        cc111 = c111.addBlock().setTextAlign("justified").addInline().addText("Cards we accept: ").setFontWeight("bold").setFontSize(FONT_SIZE_SECUNDARY).setSpaceAfter("5pt")
        cc111.addInline().addText(obj_invoice.accepted_cards).setColor(COLOR_GRAY).setFontWeight("normal").setPaddingBottom("10pt");
        c111.setPaddingTop("40pt");


        ct111.setPadding("20pt");
		ct111.addBlock("Sub-Total").setPaddingLeft("14pt");
		ct111.addBlock(`Discount (${obj_invoice.discountvalue}%)`).setColor(COLOR_RED_WINE).setPaddingLeft("14pt");
		ct111.addBlock(`Tax: Vat (${obj_invoice.taxvalue}%)`).setColor(COLOR_GRAY).setPaddingLeft("14pt");
		
		ct112.setPadding("20pt");
		ct112.addBlock(ct112.format(obj_invoice.subtotal,m_locale,NUMBER_FORMAT)+" €").setTextAlign("right").setPaddingLeft("5pt");
		ct112.addBlock(ct112.format(obj_invoice.discount,m_locale,NUMBER_FORMAT)+" €").setColor(COLOR_RED_WINE).setTextAlign("right").setPaddingLeft("5pt");
		ct112.addBlock(ct112.format(obj_invoice.tax,m_locale,NUMBER_FORMAT)+" €").setColor(COLOR_GRAY).setTextAlign("right").setPaddingLeft("5pt");

		
		cbt121 = ct121.addBlock("GRAND TOTAL:").setColor(COLOR_WHITE).setFontWeight("bold").setBackgroundColor(COLOR_GOLD).setFontSize(FONT_SIZE_NAME)
		cbt121.setPaddingTop("5pt").setPaddingBottom("5pt").setPaddingLeft("20pt").setStartIndent("20pt");

		cbt122 = ct122.addBlock(ct122.format(obj_invoice.total,m_locale,NUMBER_FORMAT)+" €").setColor(COLOR_WHITE).setFontWeight("bold").setBackgroundColor(COLOR_GOLD).setFontSize(FONT_SIZE_NAME)
		cbt122.setTextAlign("right").setPaddingTop("5pt").setPaddingBottom("5pt").setEndIndent("20pt").setPaddingRight("20pt")

		var table2 = cell2.addTable().setPageBreakInside("avoid");
		table2.addColumn();
		table2.addColumn();
		var row21 = table2.getBody().addRow();

		var c21 = row21.addCell().setLineHeight(15.0);
		var c22 = row21.addCell().setDisplayAlign("center");

		c21.addBlock("Thank You For Your Business!").setColor(COLOR_GOLD).setFontSize(FONT_SIZE_NAME).setSpaceAfter("10pt")
		c21.addBlock("Terms & Conditions:").setFontSize(FONT_SIZE_SECUNDARY)
		c21.addBlock().setColor(COLOR_GRAY).addTextLiteral("&#x00B7; "+LOREM).setFontSize(FONT_SIZE_SECUNDARY)
		c21.setTextAlign("justified");

		c22.addBlock("Thomas B. Speicher").setTextAlign("center")
		c22.addBlock("Account manager").setTextAlign("center").setColor(COLOR_GRAY).setFontSize(FONT_SIZE_SECUNDARY);


	});
    
    // =======================================================================
    // SET BODY FLOW CONTENT
    // =======================================================================
    template.setBody(body => {
    	
        var table = body.addTable();
    	table.setFontFamily(FONT_NAME);
        table.setFontSize(FONT_SIZE_PRIMARY);
        table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
	  	table.addColumn();
        // For each row, we obtain the values of each column and add it to the blocks 
	  	for (var i of obj_lines) {
	  		var row = table.getBody().addRow();
	  		var c1 = row.addCell().setLineHeight(12.0);
	  		var c2 = row.addCell().setColspan(2).setLineHeight(12.0);
	  		var c3 = row.addCell().setLineHeight(12.0);
	  		var c4 = row.addCell().setLineHeight(12.0);
	  		var c5 = row.addCell().setLineHeight(12.0);
	  		c1.addBlock(c1.format(i.DATE,m_locale,DATE_FORMAT)).setTextAlign("center");
	  		c1.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c1.setPadding("10pt").setDisplayAlign("center");
	  		c2.addBlock(i.ITEM_NAME).setFontWeight("bold");
	  		c2.addBlock(i.DESCRIPTION).setPageBreakInside("avoid").setFontSize(FONT_SIZE_SECUNDARY);
	  		c2.setTextAlign("justified").setPadding("10pt");
	  		c2.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c3.addBlock(c3.format(i.RATE,m_locale,NUMBER_FORMAT)+" €").setTextAlign("center");
	  		c3.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c3.setPadding("10pt").setDisplayAlign("center");
	  		c4.addBlock(i.QTY).setTextAlign("center");
	  		c4.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c4.setPadding("10pt").setDisplayAlign("center");
	  		var PRICE = i.RATE*i.QTY;//The price is calculated as the product between the rate and the quantity
	  		c5.addBlock(c5.format(PRICE,m_locale,NUMBER_FORMAT)+" €").setTextAlign("center").setPageBreakInside("avoid");
	  		c5.setBorderBottomStyle("solid").setBorderBottomColor(COLOR_LINE);
	  		c5.setPadding("10pt").setDisplayAlign("center");
	  	}
    });

	// =======================================================================
	// CONFIGURE BODY FOOTNOTE
	// =======================================================================
	template.setBodyFootNote(footnote => {
	});


  	// ====================================================================
  	// GENERATE PDF
  	// ====================================================================

  	var fop = template.toFOP();
  	let pdf = new Ax.fop.Processor().transform(fop);
  	return pdf;
}
</script>
// *****************************************************************************
// * DATA
// *****************************************************************************
// Needed data
var temp_invoice = {
	"id"				: 2342343,
	"date"				: new Ax.sql.Date("2020-02-19"),
	"issue_date"		: new Ax.sql.Date("2020-02-19"),
	"account_num"		: 2342323423,
	"client_name"		: "John Smith",
	"client_address"	: "Avenida Europa Edificio Alcor Plaza 2-2",
	"client_mail"		: "JohnSmith@email.com",
	"client_phone"		: "918386100",
	"paypal"			: "paypaladdress@paypal.es",
	"accepted_cards"	: "Visa",
	"company_phone"		: "345345343",
	"company_mail"		: "company@mail.com",
	"company_web"		: "www.company.com",
	"company_address"	: "old street 123",
    "taxvalue"          : 15,
    "discountvalue"     : 20,
    "tax"               : 396,
    "subtotal"          : 3300,
    "discount"          : 660,
    "total"             : 3036
}

var LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
//Needed data for the invoice lines, note we use a resultset
var m_resultset = new Ax.rs.Reader().build(
    	[
			[ new Ax.sql.Date("2020-02-19"),"Web Design", LOREM, 15, 10],
			[ new Ax.sql.Date("2020-02-19"),"Graphic Design", LOREM, 29, 50],
			[ new Ax.sql.Date("2020-02-19"),"Brand Identity", LOREM, 35, 10],
			[ new Ax.sql.Date("2020-02-19"),"Magazine Design", LOREM, 11, 50],
			[ new Ax.sql.Date("2020-02-19"),"Flyer Design", LOREM, 10, 20],
			[ new Ax.sql.Date("2020-02-19"),"Flyer Design", LOREM, 10, 20],
			[ new Ax.sql.Date("2020-02-19"),"Flyer Design", LOREM, 10, 20],
			[ new Ax.sql.Date("2020-02-19"),"Flyer Design", LOREM, 10, 20],
    	], 
    	options => {
	        options.setColumnNames(
	        	[
					"DATE",
					"ITEM_NAME",
					"DESCRIPTION",
					"RATE",
					"QTY"
		 		]
		    );
    	}
    );


// ------------------------------------------------------------------------
// OBTAIN PDF
// ------------------------------------------------------------------------

return print_invoice(temp_invoice,m_resultset);
Click here to download the PDF example

6.4 Invoice 4 example

Copy
function cvenfach_print_default(pFacidx) {

    // =========================================================================
    // Load cvenfach data.
    // =========================================================================
    var cvenfach = Ax.db.executeQuery(`
        SELECT cvenfach.*,
               cempresa.empname,
               cempresa.direcc  diremp,
               cempresa.divemp,
               cempresa_print_settings.*,
               icon_address_zipcode_town(1, ctiponac.coda2, cempresa.codpos, cempresa.poblac, cempresa.codprv, cempresa.nomprv)  pobemp,
               icon_address_zipcode_town(2, ctiponac.coda2, cempresa.codpos, cempresa.poblac, cempresa.codprv, cempresa.nomprv)  prvemp,
               icon_address_country(ctiponac.nomnac, ctiponac.coda2, ctiponac2.coda2) nacemp,
               cempresa.telef1,
               cempresa.fax1,
               cempresa.regmer,
               icon_address_zipcode_town(1, ctiponac2.coda2, cvenfach.codpos, cvenfach.poblac, cvenfach.codprv, cprovinc.nomprv) poblac,
               icon_address_zipcode_town(2, ctiponac2.coda2, cvenfach.codpos, cvenfach.poblac, cvenfach.codprv, cprovinc.nomprv) nomprv,
               icon_address_country(ctiponac2.nomnac, ctiponac2.coda2, ctiponac.coda2) nomnac,
               ctercero.nomaux,
               CAST(
                   NVL(TRIM(cvenfach.notaex), '') ||
                   NVL((SELECT CHR('010') || cdoctext.text_data
                          FROM cdoctext
                         WHERE cdoctext.tabname = 'cvenfach_print'
                           AND cdoctext.idioma  = cvenfach.idioma
                           AND cdoctext.text_code = ('cvenfach_' || LOWER(ctiponac2.coda2) || '_notaex') ), '')
               AS lvarchar) notaex,
               CASE WHEN (ctiponac.coda2 = 'PT' OR ctiponac.coda3 = 'PRT') THEN ABS(cvenfach.imptot) ELSE cvenfach.imptot END imptot_print,
               icon_get_imploc(0, cvenfach.empcode, cvenfach.moneda, cvenfach.fecfac, cvenfach.cambio, cvenfach.imptot)       imptot_loc,
               cvenfacd.titdoc,
               cmonedas.symbol
          FROM cvenfach
               ,OUTER cvenfacd
               ,cempresa 
               ,OUTER cempresa_print_settings
               ,OUTER ctiponac
               ,OUTER ctercero 
               ,OUTER ctiponac ctiponac2
               ,OUTER cprovinc
               ,OUTER cmonedas
         WHERE cvenfacd.codigo  = cvenfach.tipdoc 
           AND cvenfach.empcode = cempresa.empcode  
           AND cempresa_print_settings.empcode = cempresa.empcode  
           AND cempresa.codnac  = ctiponac.codigo  
           AND cvenfach.tercer  = ctercero.codigo  
           AND cvenfach.codnac  = ctiponac2.codigo  
           AND cvenfach.codnac  = cprovinc.codnac  
           AND cvenfach.codprv  = cprovinc.codigo 
           AND cvenfach.moneda  = cmonedas.codigo 
           AND cvenfach.facidx  = ?
        `, pFacidx).toOne().setRequired(`Invoice facidx: ${pFacidx} not found.`);
    
    // =========================================================================
    // Load cvenfach_tax data.
    // =========================================================================
    var cvenfach_tax = Ax.db.executeQuery(`
        SELECT  cvenfach_tax.tax_order,
                cvenfach_tax.tax_oper,
                ctax_operation.oper_name,
                cvenfach_tax.tax_code,
                ctax_type.type_name,
                cvenfach_tax.tax_porcen,
                cvenfach_tax.tax_porded,
                cvenfach_tax.tax_basimp,
                cvenfach_tax.tax_basnimp,        
                cvenfach_tax.tax_cuoded,
                cvenfach_tax.tax_cuonded,
                (cvenfach_tax.tax_basimp + cvenfach_tax.tax_basnimp +        
                cvenfach_tax.tax_cuoded + cvenfach_tax.tax_cuonded ) lintot,
                cvenfach_tax.tax_mainkey,
                cvenfach_tax.tax_rule,
                cvenfach_tax.tax_manual
          FROM cvenfach_tax, OUTER ctax_type, OUTER ctax_operation
         WHERE cvenfach_tax.tax_code    = ctax_type.type_code
           AND ctax_operation.oper_code = cvenfach_tax.tax_oper
           AND cvenfach_tax.facidx   = ?
    `, pFacidx).toMemory();

    // =========================================================================
    // Load cvenefec data.
    // =========================================================================
    var cvenefec = Ax.db.executeQuery(`
        SELECT cvenefec.*, 
               icon_get_iban(?,
                             ?,
                             ?,
                             'C',
                             cvenefec.tipefe,
                             ?,
                             'cvenfach',
                             cvenefec.facidx) iban,             
               ctipoefe.nomefe, 
               ctipoefe.domban,
               '${cvenfach.moneda}' moneda
          FROM cvenefec, OUTER ctipoefe
         WHERE cvenefec.tipefe = ctipoefe.codigo
           AND ctipoefe.clase  = "C"
           AND cvenefec.facidx = ?
         ORDER BY fecven
        `, cvenfach.empcode, cvenfach.codper, cvenfach.numban, cvenfach.ctafin, pFacidx).toMemory();

    if (cvenefec.getRowCount() == 0) {
        throw new Error(`No rows found at cvenefec for facidx: ${pFacidx}`);
        /***
        var cvenefec = Ax.db.executeQuery(`
            SELECT ctipoefe.nomefe, 
                   icon_get_iban(?,
                                 ?,
                                 ?,
                                 'C',
                                 cvenfach.tipefe,
                                 ?,
                                 'cvenfach',
                                 cvenfach.facidx) iban,                                
                   ctipoefe.domban,
                   cvenfach.imptot impdiv,                   
                   cvenfach.moneda
              FROM cvenfach, OUTER ctipoefe
             WHERE cvenfach.tipefe = ctipoefe.codigo
               AND ctipoefe.clase  = "C"
               AND cvenfach.facidx = ?
            `, cvenfach.empcode, cvenfach.codper, cvenfach.numban, cvenfach.ctafin, pFacidx).toMemory();
        ***/
    }

    // =========================================================================
    // Load cvenfacl data.
    // =========================================================================
    var cvenfacl = Ax.db.executeQuery(`
        SELECT cvenfacl.*, 
               CASE WHEN cvenfacl.desamp IS NOT NULL THEN cvenfacl.desamp
                    ELSE carticul.nomart
                 END desamp,       
               carticul.unimed,
               ctax_type1.type_name type_name1, ctax_type1.type_porcen type_porcen1, ctax_type1.type_class type_class1,
               ctax_type2.type_name type_name2, ctax_type2.type_porcen type_porcen2, ctax_type2.type_class type_class2,
               ctax_type3.type_name type_name3, ctax_type3.type_porcen type_porcen3, ctax_type3.type_class type_class3,
               ctax_type4.type_name type_name4, ctax_type4.type_porcen type_porcen4, ctax_type4.type_class type_class4
          FROM cvenfacl, OUTER carticul, OUTER ctax_type ctax_type1, OUTER ctax_type ctax_type2,
               OUTER ctax_type ctax_type3, OUTER ctax_type ctax_type4
         WHERE cvenfacl.codart    = carticul.codart
           AND cvenfacl.tax_code1 = ctax_type1.type_code
           AND cvenfacl.tax_code2 = ctax_type2.type_code
           AND cvenfacl.tax_code3 = ctax_type3.type_code
           AND cvenfacl.tax_code4 = ctax_type4.type_code
           AND cvenfacl.facidx    = ?
         ORDER BY numero
        `, pFacidx).toMemory();

    // =========================================================================
    // RENDER INVOICE JSON OBJECT TO PDF
    // =========================================================================

    // =========================================================================
    // STYLE VARIABLES
    // =========================================================================
    const LOCALE       = cvenfach.idioma          || 'es';
    const FONT_NAME    = cvenfach.font_name       || "Noto Sans";
    //const BACKCOLOR1 = cvenfach.color_primary   || '#f9eec6';
    const BACKCOLOR1   =  '#f9eec6';
    const BACKCOLOR2   = cvenfach.color_secondary || '#EEEEEE';
    
    const FONT_SIZE    = 8;
    const BORDERWIDTH  = '0.25pt';
    const BORDERRADIUS = '2pt';
    const PADDING      = '2pt';
    const NumberFormat = new Ax.text.NumberFormat(LOCALE);

    // =========================================================================
    // LABEL VARIABLES
    // =========================================================================
    const LBL_FACTURA        = Ax.ext.webapp.getLabel('PRN_DOCTITLE_FACTURA', LOCALE);
    const LBL_IDENTIFICACION = Ax.ext.webapp.getLabel('HDR_IDENTIFICACION',   LOCALE);
    const LBL_CLIENTE        = Ax.ext.webapp.getLabel('HDR_CLIENTE',          LOCALE);
    const LBL_IMPUESTOS      = Ax.ext.webapp.getLabel('HDR_IMPUESTOS',        LOCALE);
    const LBL_CONDCOBRO      = Ax.ext.webapp.getLabel('PRN_COND_COBRO',       LOCALE);
    const LBL_NOTAS          = Ax.ext.webapp.getLabel('HDR_NOTAS',            LOCALE);
    const LBL_REFERENCIA     = Ax.ext.webapp.getColumn('virtualcon',   'abbr_ref_c',         LOCALE).getColMemo();
    const LBL_NIF            = Ax.ext.webapp.getColumn('virtualcon',   'abbr_taxpayer_id_c', LOCALE).getColMemo();
    const LBL_TEL            = Ax.ext.webapp.getColumn('virtualcon',   'abbr_phone_c',       LOCALE).getColMemo();
    const LBL_FAX            = Ax.ext.webapp.getColumn('virtualcon',   'abbr_fax_c',         LOCALE).getColMemo();
    const LBL_NUMFACTURA     = Ax.ext.webapp.getColumn('virtualcon',   'numfac',             LOCALE).getColMemo();
    const LBL_FECFACTURA     = Ax.ext.webapp.getColumn('cvenfach',     'fecfac',             LOCALE).getColMemo();
    const LBL_IMPORTETOTAL   = Ax.ext.webapp.getColumn('cvenfach',     'imptot',             LOCALE).getColMemo();
    const LBL_MONEDA         = Ax.ext.webapp.getColumn('cvenfach',     'moneda',             LOCALE).getColMemo();
    const LBL_DESCRIPCION    = Ax.ext.webapp.getColumn('cvenfacl',     'desamp',             LOCALE).getColMemo();
    const LBL_CANTIDAD       = Ax.ext.webapp.getColumn('cvenfacl',     'cantid',             LOCALE).getColMemo();
    const LBL_PRECIO         = Ax.ext.webapp.getColumn('cvenfacl',     'precio',             LOCALE).getColMemo();
    const LBL_DTOLIN         = Ax.ext.webapp.getColumn('cvenfacl',     'dtolin',             LOCALE).getColMemo();
    const LBL_TOTNET         = Ax.ext.webapp.getColumn('cvenfacl',     'totnet',             LOCALE).getColMemo();
    const LBL_OPERACION      = Ax.ext.webapp.getColumn('cvenfach_tax', 'tax_oper',           LOCALE).getColMemo();
    const LBL_DESIMPUESTO    = Ax.ext.webapp.getColumn('ctax_type',    'type_name',          LOCALE).getColMemo();
    const LBL_PORCEN         = Ax.ext.webapp.getColumn('cvenfach_tax', 'tax_porcen',         LOCALE).getColMemo();
    const LBL_BASIMP         = Ax.ext.webapp.getColumn('cvenfach_tax', 'tax_basimp',         LOCALE).getColMemo();
    const LBL_CUODED         = Ax.ext.webapp.getColumn('cvenfach_tax', 'tax_cuoded',         LOCALE).getColMemo();
    const LBL_SUMA           = Ax.ext.webapp.getColumn('cvenfach_tax', 'lintot',             LOCALE).getColMemo();
    const LBL_NOMEFE         = Ax.ext.webapp.getColumn('ctipoefe',     'nomefe',             LOCALE).getColMemo();
    const LBL_IBAN           = Ax.ext.webapp.getColumn('cterbanc',     'iban',               LOCALE).getColMemo();
    const LBL_FECVEN         = Ax.ext.webapp.getColumn('cvenefec',     'fecven',             LOCALE).getColMemo();
    const LBL_IMPORT         = Ax.ext.webapp.getColumn('cvenefec',     'import',             LOCALE).getColMemo();

    var   Date_Format        = LOCALE == "es" ? "dd/MM/yyyy" : "MM/dd/yyyy";

    // =========================================================================
    // CONFIGURE FOP ROOT LAYOUT
    // =========================================================================
    var template = new Ax.fop.SinglePageTemplate("A4");

    template.setRoot(root => {
        //root.setDebug("*");

        // Default Page layout    
        root.getSimplePageMaster().getRegionBefore().setExtent(6.5);
        root.getSimplePageMaster().getRegionStart().setExtent(1.0);
        root.getSimplePageMaster().getRegionEnd().setExtent(1.0);

        // Get the FOPSimplePageMaster now (we only have one)
        // after adding the first .. we can not call again
        // cause we have two ... and dont know witch one ..
        var spm       = root.getSimplePageMaster();
        var pageOnly  = root.addSimplePageMaster("PageOnly").apply(spm);
        var pageFirst = root.addSimplePageMaster("PageFirst").apply(spm);
        var pageRest  = root.addSimplePageMaster("PageRest").apply(spm);
        var pageLast  = root.addSimplePageMaster("PageLast").apply(spm);

        // In last page we need to acommodate Tax and Notes table. So we requie more space
        pageFirst.setMargins(0, 0, 0.5, 0);
        pageFirst.getRegionAfter().setExtent(1);
        pageRest.setMargins(0, 0, 0.5, 0);
        pageRest.getRegionAfter().setExtent(1);
        pageLast.setMargins(0, 0, 0.5, 0);
        pageLast.getRegionAfter().setExtent(9);
        pageOnly.setMargins(0, 0, 0.5, 0);
        pageOnly.getRegionAfter().setExtent(9);

        // Create a pagesequence master
        var master = root.createPageSequenceMaster("master");    
        master.addConditionalPageMasterReference(root.getSimplePageMaster("PageOnly"),  "only");
        master.addConditionalPageMasterReference(root.getSimplePageMaster("PageFirst"), "first");
        master.addConditionalPageMasterReference(root.getSimplePageMaster("PageRest"),  "rest");
        master.addConditionalPageMasterReference(root.getSimplePageMaster("PageLast"),  "last");
        root.addPageSequenceMaster(master);
        root.getPageSequence().setMasterReferenceName("master");        
    });

    // =========================================================================
    // CONFIGURE BEFORE REGION
    // =========================================================================
    // =========================================================================
    // (beforeLeft)                             (beforeRight)
    //           
    // LOGO empcode                             empname  
    //                                          diremp
    //                                          pobemp
    //                                          prvemp
    //                                          nacemp  
    //                                          "NIF:"  emp_cif
    //                                          "Tel:"  telef1  "Fax:"  fax1
    //
    // FACTURA
    //
    // Identificación                           Cliente
    //
    // "Numero factura:" tercer                 nombre        
    // "Fecha:"          fecfac                 nomaux
    // "Referencia:"     refaux                 direcc
    // "Descuento:"      dtocab                 poblac
    // "Importe total:"  imptot                 nomprv
    //                                          nomnac
    //                                          cif
    // =========================================================================
    template.setBefore(before => {
        // =====================================================================
        // ROW 1: LOGO + SPC + DATOS EMPRESA
        // =====================================================================

        let row1       = before.addBlock();
        let block_logo = row1.addInlineContainer()
                                    .setWidth("9cm")
                                    .addBlock();
        if (cvenfach.logo_top_image != null) {
            block_logo.addExternalGraphic(cvenfach.logo_top_image).setContentWidth(3.5).setVerticalAlign("top");
        }
        let block_sp1  = row1.addInlineContainer()
                               .setWidth("1cm")
                               .addBlock();
        let block_emp  = row1.addInlineContainer()
                               .setWidth("9cm")
                               .addBlock(cvenfach.empname).setFontFamily(FONT_NAME).setFontSize(9)
                               .addBlock(cvenfach.diremp)
                               .addBlock(cvenfach.pobemp)
                               .addBlock(cvenfach.prvemp)
                               .addBlock(cvenfach.nacemp)
                               .addBlock(LBL_NIF + cvenfach.emp_cif).setSpaceBefore("0.25cm");
        if (cvenfach.telef1 || cvenfach.fax1) {
            block_emp.addBlock(LBL_TEL + cvenfach.telef1 + "   " + LBL_FAX + (cvenfach.fax1 || ""));
        }
        
        // =====================================================================
        // ROW 2: INVOICE DATA + CUSTOMER DATA
        // =====================================================================
        let row2 = before.addBlock().setSpaceBefore("0.5cm");
        var block_fac = row2.addInlineContainer()
                            .setWidth("9.0cm")
                            .addBlock()
                            .setFontFamily(FONT_NAME)
                            .setFontSize(FONT_SIZE);                                

        block_fac.addBlock(LBL_FACTURA)
                 .setFontWeight("bold")
                 .setBackgroundColor(BACKCOLOR1)
                 .setPadding(PADDING)
                 .setMargin(0)
                 .setProperty("xmlns:fox", "http://xmlgraphics.apache.org/fop/extensions")
                 .setProperty("fox:border-radius", BORDERRADIUS)
                 .setBorderStyle("solid")
                 .setBorderWidth("0.5")
                 ;

        var table = block_fac.addTable().setMarginTop("0.2cm");
        table.addColumn().setColumnWidth(2.5);
        table.addColumn().setColumnWidth(4);

        table.getBody().addRow([LBL_NUMFACTURA, cvenfach.docser]);
        table.getBody().addRow([LBL_FECFACTURA, new Ax.util.Date(cvenfach.fecfac).format(Date_Format)]);
        table.getBody().addRow([LBL_REFERENCIA, cvenfach.refaux || ' ']);
        table.getBody().addRow([LBL_IMPORTETOTAL, NumberFormat.format(cvenfach.imptot, "###,###.00") + " " + cvenfach.symbol]);
        if (cvenfach.moneda != cvenfach.divemp) {
            table.getBody().addRow([LBL_MONEDA, cvenfach.moneda || ' ']);
        }

        let block_sp2 = row2.addInlineContainer()
                            .setWidth("1.0cm")
                            .addBlock("\t");
        // Cliente 
        var block_cli = row2.addInlineContainer()
                            .setWidth("9.0cm")
                            .addBlock().setFontFamily(FONT_NAME)
                                       .setFontSize(FONT_SIZE);   
                                
        block_cli.addBlock(LBL_CLIENTE + " (" + cvenfach.tercer + ")")
                 .setFontWeight("bold")
                 .setBackgroundColor(BACKCOLOR1)
                 .setMargin(0)
                 .setPadding(PADDING)
                 .setProperty("xmlns:fox", "http://xmlgraphics.apache.org/fop/extensions")
                 .setProperty("fox:border-radius", BORDERRADIUS)
                 .setBorderStyle("solid")
                 .setBorderWidth("0.5")
                 ;

        block_cli.addBlock(cvenfach.nombre).setMargin(0).setPaddingLeft(PADDING).setPaddingTop("0.2cm")                                       
                   .addBlock(cvenfach.nomaux || '')                  
                   .addBlock(cvenfach.direcc || '')                                       
                   .addBlock(cvenfach.poblac || '')                                      
                   .addBlock(cvenfach.nomprv || '')                                       
                   .addBlock(cvenfach.nomnac || '')
                   .addBlock(LBL_NIF + cvenfach.emp_cif).setSpaceBefore("0.25cm")
    });

    // =========================================================================
    // CONFIGURE BODY REGION
    // =========================================================================
    // =========================================================================
    // Descripción      Cantidad        Precio      Importe
    // desamp           cantid          precio      totnet
    // =========================================================================
    template.setBody(body => {
        body.getWrapper().setFontSize(FONT_SIZE);
		body.getWrapper().setFontFamily(FONT_NAME);

        var table = body.addTable();
        table.setProperty("font-family", FONT_NAME);
        table.setProperty("font-size", FONT_SIZE);
        table.setProperty("border-before-width.conditionality","retain");
        table.setProperty("border-after-width.conditionality","retain");
        table.setProperty("xmlns:fox", "http://xmlgraphics.apache.org/fop/extensions");
        table.setProperty("fox:border-radius", BORDERRADIUS);
        table.setBorderStyle("solid");
        table.setBorderWidth(BORDERWIDTH);    
        table.setBorderLeftWidth("1pt");    
        table.setBorderRightWidth("1pt");    

        table.addColumn(LBL_DESCRIPCION).setBorderRightStyle("solid").setBorderRightWidth(BORDERWIDTH).setColumnWidth(11);
        table.addColumn(LBL_CANTIDAD).setBorderRightStyle("solid").setBorderRightWidth(BORDERWIDTH).setColumnWidth(2);
        table.addColumn(LBL_PRECIO).setBorderRightStyle("solid").setBorderRightWidth(BORDERWIDTH).setColumnWidth(2);
        table.addColumn(LBL_DTOLIN).setBorderRightStyle("solid").setBorderRightWidth(BORDERWIDTH).setColumnWidth(1.5);
        table.addColumn(LBL_TOTNET).setColumnWidth(2.5);
        table.getHeader().getRows().forEach(row => {
            row.setBackgroundColor(BACKCOLOR2);
            row.forEach(cell => {
                cell.setPadding(PADDING);
                cell.setFontWeight("bold");
                cell.setBorderBottomStyle("solid");
                cell.setBorderBottomWidth(BORDERWIDTH);
            });
        });
        let nrow = 0;
        for (var cvenfaclRow of cvenfacl) {
            nrow++;
            var row = table.getBody().addRow().setBackgroundColor("white");
            row.addCell().addBlock(cvenfaclRow.desamp).setLinefeedTreatment('preserve');
            row.addCell().addBlock(NumberFormat.format(cvenfaclRow.cantid, "###,###.00")).setTextAlign('right');
            row.addCell().addBlock(NumberFormat.format(cvenfaclRow.precio, "###,###.00")).setTextAlign('right');
            row.addCell().addBlock(NumberFormat.format(cvenfaclRow.dtolin, "0.00")).setTextAlign('right');
            row.addCell().addBlock(NumberFormat.format(cvenfaclRow.totnet, "###,###.00")).setTextAlign('right');
            row.forEach(cell => {
                cell.setPadding(PADDING);
                if (nrow % 3 == 0) {
                    cell.setBorderBottomStyle("dotted");
                    cell.setBorderBottomWidth("0.3");
                }  
            });
        }                    
    });

    // =========================================================================
    // CONFIGURE PAGE START REGION
    // =========================================================================
    template.setStart(start => {
        // Texto izquierda de página para todos los tipos de página
        if (cvenfach.text_region_start) {
            start.addBlockContainer()
                .setPosition("absolute")
                .addBlock(cvenfach.text_region_start)
                .setTextAlign('center')
                .setFontSize(6);
        }    
    });

    // =========================================================================
    // CONFIGURE PAGE END REGION
    // =========================================================================
    template.setEnd(end => {
        // Texto derecha de página para todos los tipos de página
        if (cvenfach.text_region_end) {
            end.addBlockContainer()
                .setPosition("absolute")
                .addBlock(cvenfach.text_region_end)
                .setTextAlign('center')
                .setFontSize(6);
        }
    });

    // =========================================================================
    // CONFIGURE LAST PAGE AFTER REGION
    // =========================================================================
    template.setAfter(after => {

        if (after.getMasterName() == 'PageLast' || after.getMasterName() == 'PageOnly') {
            // ---------------------------------------------------------------------
            // Impuestos
            // Operación  Descripción   %           Base imponible  Cuota deducible Suma
            // tax_oper   type_name    tax_porcen   tax_basimp      tax_cuoded      lintot
            // ---------------------------------------------------------------------
            if (cvenfach_tax.getRowCount()) {
                after.addBlock(LBL_IMPUESTOS)
                    .setSpaceBefore("5pt")
                    .setFontWeight("bold")
                    .setFontFamily(FONT_NAME)
                    .setFontSize(FONT_SIZE)
                    .setBackgroundColor(BACKCOLOR1)
                    .setPadding(PADDING)
                    .setMargin(0)
                    .setProperty("xmlns:fox", "http://xmlgraphics.apache.org/fop/extensions")
                    .setProperty("fox:border-radius", BORDERRADIUS)
                    .setBorderStyle("solid")
                    .setBorderWidth("0.5")
                    ;

                var table = after.addTable();
                table.setProperty("font-family", FONT_NAME);
                table.setProperty("font-size", FONT_SIZE);
                table.setSpaceBefore("4pt");
                table.getHeader().setBorderStyle("solid");
                table.getHeader().setBorderWidth(BORDERWIDTH);               
                table.addColumn(LBL_OPERACION).setColumnWidth(2.5).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_DESIMPUESTO).setColumnWidth(7).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_PORCEN).setColumnWidth(1.5).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_BASIMP).setColumnWidth(2.5).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_CUODED).setColumnWidth(2.5).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_SUMA).setColumnWidth(3.0).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.getHeader().getRows().forEach(row => {
                    row.setBackgroundColor(BACKCOLOR2);
                    row.forEach(cell => {
                        cell.setPadding(PADDING);
                    });
                });

                for (var cvenfach_taxRow of cvenfach_tax) {
                    let row = table.getBody().addRow([cvenfach_taxRow.tax_oper,
                                                    cvenfach_taxRow.type_name,
                                                    NumberFormat.format(cvenfach_taxRow.tax_porcen, "0.00"),
                                                    NumberFormat.format(cvenfach_taxRow.tax_basimp, "###,##0.00"),
                                                    NumberFormat.format(cvenfach_taxRow.tax_cuoded, "###,##0.00"),
                                                    NumberFormat.format(cvenfach_taxRow.lintot, "###,##0.00")
                                                    ]);
                    row.forEach(cell => {
                        cell.setPadding(PADDING);
                        if (cell.getColumnIndex() > 1) {
                            cell.setTextAlign('right');
                        }
                    });                 
                }
            } 
            
            // ---------------------------------------------------------------------
            // Condiciones de cobro
            // Descripción  IBAN    Fecha   Importe     Moneda
            // nomefe       iban    fecven  impdiv      moneda    
            // ---------------------------------------------------------------------
            if (cvenefec.getRowCount()) {
                after.addBlock(LBL_CONDCOBRO)
                    .setSpaceBefore("4pt")
                    .setFontWeight("bold")
                    .setFontFamily(FONT_NAME)
                    .setFontSize(FONT_SIZE)
                    .setBackgroundColor(BACKCOLOR1)
                    .setPadding(PADDING)
                    .setMargin(0)
                    .setProperty("xmlns:fox", "http://xmlgraphics.apache.org/fop/extensions")
                    .setProperty("fox:border-radius", BORDERRADIUS)
                    .setBorderStyle("solid")
                    .setBorderWidth("0.5")
                    ;
                var table = after.addTable();
                table.setProperty("font-family", FONT_NAME);
                table.setProperty("font-size", FONT_SIZE);
                table.setBorderStyle("solid");
                table.setBorderWidth(BORDERWIDTH);
                table.setSpaceBefore(cvenfach_tax.getRowCount() ? "4pt" : "0pt");

                table.addColumn(LBL_NOMEFE).setColumnWidth(3).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_IBAN).setColumnWidth(5).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_FECVEN).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_IMPORT).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.addColumn(LBL_MONEDA).setBorderStyle("solid").setBorderWidth(BORDERWIDTH);
                table.getHeader().getRows().forEach(row => {
                    row.setBackgroundColor(BACKCOLOR2);
                    row.setBorderWidth(BORDERWIDTH);
                    row.forEach(cell => {
                        cell.setPadding(PADDING);
                    });
                });            

                for (var cvenefecRow of cvenefec) {
                    var row = table.getBody().addRow([cvenefecRow.nomefe,
                                                    cvenefecRow.iban,
                                                    new Ax.util.Date(cvenefecRow.fecven).format(Date_Format),
                                                    NumberFormat.format(cvenefecRow.impdiv, "###,###.00"),
                                                    cvenefecRow.moneda
                                                    ]);
                    row.forEach(cell => {
                        cell.setPadding(PADDING);
                        cell.setBorderStyle("solid");
                        cell.setBorderWidth(BORDERWIDTH);
                        if (cell.getColumnIndex() == 3) {
                            cell.setTextAlign('right');
                        }
                    });                                  
                }            
            }

            // ---------------------------------------------------------------------
            // Notas
            // ---------------------------------------------------------------------
            after.addBlock(LBL_NOTAS)
                .setSpaceBefore("4pt")
                .setFontWeight("bold")
                .setFontFamily(FONT_NAME)
                .setFontSize(FONT_SIZE)
                .setBackgroundColor(BACKCOLOR1)
                .setPadding(PADDING)
                .setMargin(0)
                .setProperty("xmlns:fox", "http://xmlgraphics.apache.org/fop/extensions")
                .setProperty("fox:border-radius", BORDERRADIUS)
                .setBorderStyle("solid")
                .setBorderWidth("0.5")
                ;

            after.addBlockContainer()
                .addBlock(cvenfach.notaex)
                .setFontFamily(FONT_NAME)
                .setFontSize(FONT_SIZE)
                .setMarginTop("0.2")
                .setPadding(PADDING);
        }

        row = after.addBlock().setMarginTop("5pt");
        let block_text = row.addInlineContainer().setWidth("16cm")
                .addBlock();
        let block_page = row.addInlineContainer().setWidth("3cm")
                .addBlock()
                .setFontFamily(FONT_NAME)
                .setFontSize(6)
                .setTextAlign("end");

        // Texto final de página para todos los tipos de página
        if (cvenfach.text_region_after) {
            block_text.addBlock(cvenfach.text_region_after)
                .setFontSize(6);
        }

        var totalPageNumbeId = after.getRoot().getPageSequence().getTotalPageNumberCitation();
        block_page.addInline()
            //.addText("Pag. ")
            .putPageNumber()
            .addText(" - ")
            .putPageNumberCitation(totalPageNumbeId);
    });

    // =========================================================================
    // GENERATE PDF
    // =========================================================================
    var fop = template.toFOP();
    console.log(fop);
    let pdf = new Ax.fop.Processor().transform(fop);

    return pdf;
};

//return cvenfach_print_default(3080);

6.5 Delivery Note

Copy

Delivery Example

var logo_albaran = "base64:,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AD+AAAA4QklNA/IAAAAAAAoAAP///////wAAOEJJTQQNAAAAAAAEAAAAHjhCSU0EGQAAAAAABAAAAB44QklNA/MAAAAAAAkAAAAAAAAAAAEAOEJJTScQAAAAAAAKAAEAAAAAAAAAAjhCSU0D9QAAAAAASAAvZmYAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAAQAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAA4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQQeAAAAAAAEAAAAADhCSU0EGgAAAAADUQAAAAYAAAAAAAAAAAAAAHgAAAGYAAAADgBhAGwAYgBhAHIAYQBuAF8AaABlAGEAZABlAHIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAZgAAAB4AAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAAB4AAAAAFJnaHRsb25nAAABmAAAAAZzbGljZXNWbExzAAAAAU9iamMAAAABAAAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAAGb3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQAAAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAAeAAAAABSZ2h0bG9uZwAAAZgAAAADdXJsVEVYVAAAAAEAAAAAAABudWxsVEVYVAAAAAEA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AG8AdABvAHMAaABvAHAAAAAXAEEAZABvAGIAZQAgAFAAaABvAHQAbwBzAGgAbwBwACAAQwBDACAAMgAwADEAOAAAAAEAOEJJTQQGAAAAAAAHAAgAAAABAQD/4RJ6aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzE0MCA3OS4xNjA0NTEsIDIwMTcvMDUvMDYtMDE6MDg6MjEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjE2NDZhYzdhLWFkMDYtMjY0ZS05NTU4LWZiM2Y4MzRiM2VjNCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2YTJkOWFmMS04YWEyLTQ1ZWUtYjhjMy0wMDk2ZDc3MGMwMGYiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0iQjc1NzMyQzNBNDZCQkZERUQzRjlDMkI3QTJFMkI5ODAiIGRjOmZvcm1hdD0iaW1hZ2UvanBlZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9IkFwcGxlIFJHQiIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDctMTNUMTE6NDY6MzUrMDI6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA3LTEzVDEzOjI5OjA0KzAyOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE4LTA3LTEzVDEzOjI5OjA0KzAyOjAwIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChNYWNpbnRvc2gpIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NWMxMjZiMGQtZDA3YS00YWRjLWE2NjctODQ4ZTc4ZTBmZDYxIiBzdEV2dDp3aGVuPSIyMDE4LTA3LTEzVDExOjUzOjQ0KzAyOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGltYWdlL2pwZWcgdG8gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iZGVyaXZlZCIgc3RFdnQ6cGFyYW1ldGVycz0iY29udmVydGVkIGZyb20gaW1hZ2UvanBlZyB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo4ZmY5OTJlMy01MzZiLTQzYWItYmZmZC00MDUyNWFkZTkzMmIiIHN0RXZ0OndoZW49IjIwMTgtMDctMTNUMTE6NTM6NDQrMDI6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChNYWNpbnRvc2gpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpkODlmZWQ2NS0xMWNkLTQ4Y2YtYjc3Ni05MmU1Y2I4NzA3NmUiIHN0RXZ0OndoZW49IjIwMTgtMDctMTNUMTM6Mjk6MDQrMDI6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChNYWNpbnRvc2gpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9qcGVnIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJkZXJpdmVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJjb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL2pwZWciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjZhMmQ5YWYxLThhYTItNDVlZS1iOGMzLTAwOTZkNzcwYzAwZiIgc3RFdnQ6d2hlbj0iMjAxOC0wNy0xM1QxMzoyOTowNCswMjowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKE1hY2ludG9zaCkiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOmQ4OWZlZDY1LTExY2QtNDhjZi1iNzc2LTkyZTVjYjg3MDc2ZSIgc3RSZWY6ZG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjJmMzI1Y2JiLTYzOTYtMTU0Yy05OGM5LTc5ZmFkNDQyZmUxYiIgc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPSJCNzU3MzJDM0E0NkJCRkRFRDNGOUMyQjdBMkUyQjk4MCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+/+ICOElDQ19QUk9GSUxFAAEBAAACKEFEQkUCEAAAbW50clJHQiBYWVogB88ABgADAAAAAAAAYWNzcEFQUEwAAAAAbm9uZQAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1BREJFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKY3BydAAAAPwAAAAyZGVzYwAAATAAAABkd3RwdAAAAZQAAAAUYmtwdAAAAagAAAAUclRSQwAAAbwAAAAOZ1RSQwAAAcwAAAAOYlRSQwAAAdwAAAAOclhZWgAAAewAAAAUZ1hZWgAAAgAAAAAUYlhZWgAAAhQAAAAUdGV4dAAAAABDb3B5cmlnaHQgMTk5OSBBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZAAAAGRlc2MAAAAAAAAACkFwcGxlIFJHQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81EAAQAAAAEWzFhZWiAAAAAAAAAAAAAAAAAAAAAAY3VydgAAAAAAAAABAc0AAGN1cnYAAAAAAAAAAQHNAABjdXJ2AAAAAAAAAAEBzQAAWFlaIAAAAAAAAHm9AABBUgAABLlYWVogAAAAAAAAVvgAAKwvAAAdA1hZWiAAAAAAAAAmIgAAEn8AALFw/+4ADkFkb2JlAGRAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQEBAQEBAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAeAGYAwERAAIRAQMRAf/dAAQAM//EAaIAAAAGAgMBAAAAAAAAAAAAAAcIBgUECQMKAgEACwEAAAYDAQEBAAAAAAAAAAAABgUEAwcCCAEJAAoLEAACAQMEAQMDAgMDAwIGCXUBAgMEEQUSBiEHEyIACDEUQTIjFQlRQhZhJDMXUnGBGGKRJUOhsfAmNHIKGcHRNSfhUzaC8ZKiRFRzRUY3R2MoVVZXGrLC0uLyZIN0k4Rlo7PD0+MpOGbzdSo5OkhJSlhZWmdoaWp2d3h5eoWGh4iJipSVlpeYmZqkpaanqKmqtLW2t7i5usTFxsfIycrU1dbX2Nna5OXm5+jp6vT19vf4+foRAAIBAwIEBAMFBAQEBgYFbQECAxEEIRIFMQYAIhNBUQcyYRRxCEKBI5EVUqFiFjMJsSTB0UNy8BfhgjQlklMYY0TxorImNRlUNkVkJwpzg5NGdMLS4vJVZXVWN4SFo7PD0+PzKRqUpLTE1OT0laW1xdXl9ShHV2Y4doaWprbG1ub2Z3eHl6e3x9fn90hYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A16/b/V+ve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r/0Nev2/1fr3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de6/9HXr9v9X697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuv/S16/b/V+ve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r/09ev2/1fr3v3Xuve/de697917r3v3Xuve/de67AvwOSeAB+ffuvdbCnxP/4Tn/LH5GdTbd7d3pvvYnRGL3niabO7R2vu6hzuZ3lW4TI08VXicvmcXioI6bb9Nk6aVZYoZp2qxGys8SXANCwHWq9VufPb+XZ8gf5ePYmI2T3RR4jKYTdtJWZDYfYu0p6qs2hvClxssMOThpJaymo67HZfFvURGpoqqKOaNJo3GqN1Y2BB690Q33vrfXvfuvdH8/lrfBnNfzBvlBt7oii3INmbbp8Jld7dgbtWlFfWYbZmAlooK0Yihd44azN5OvyVNSUqyMsaPMZXukbA6JoK9a62E/n1/wAJyekeqPjRvntz4u9gdoy786n2pkt45vbHZGV2/uLFb5wmApDX52LG1GG23tuo29m4sdBNPBf7mnmZBEVjv5PdAxrQ9aB608PbnVutwb+Xv/wnR6T7g+Mmwe5/lJv3s+LeXb+0cVvjbW1utcvgNu43Zu2NzUKZPbT5Sry+3Nyz53N12IqYKqRQKaCn8viKyMpf22WNcdVr1QD/ADM/ghmf5efydy/R9TuR95bVye3sXvvrrddRSJQV+Z2Zm6rI0FOMtQxPJDT5bF5bEVdHUGM+KV6fyIFVwouDUV631Xv731vr3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917pe9XdZ727m7G2V1R1xgqrcu++wdyYram1sHRqWmr8vl6qOlpkZ7FaeliLmSeZ7RwQI8jkIrEa6919F34r/wAmH4NdEdBbW6z7F+P3UHde/mwNK/ZHZvYWysPurPZzdVTTB83Pt3LZ2jqMltTBUtVI0VDDQPSMlPGjyapi8jNlifPqtetIX+a31/8AETq/5ndi7J+F2SNd1VhI6GmzFLRZabP7XwO/1843Tt7Zmdqp6qrym3sROI4g0k04jqRNEkrxop9uCtM9bHVb/vfW+ve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuv/9TXr9v9X697917r3v3Xuve/de697917r3v3XurMf5R3w/l+aHzh6o66yeOet662hXDtLtlzHI1KNi7Lq6OrlxNS6qVQbrzk1FiRcggVrOL6CPeiaDrR6+mxHHHFGkUSJHFGixxxxqEjjjQBUREUBURFFgBwB7Z6r1U9/Ok+Ho+YfwW7HweCxYyHZvU6Ht/rAwwiWunzO1KOqbO7fpSLOx3RtWaspFTUENS0Dtfxj3ZTQ9bHXzWCLcHgjgg/j271brr37r3WyB/wmI/7Lr7I/wDFdt0/+9lsf3R+HWj1ug/L7/slH5K/+II7Y/8AeGznug4jqvXyfvb3V+vq4fCf/sjb4nf+K29H/wDvtNs+2Oqdacn/AAqJ/wCy4umP/FW9s/8Av0+2fbicOrDrXdwPXPYO6qZqzbGxd4bipEJD1WC21mctTKQuohp6CiniBCm55+nu3W+k7k8RlcJVyUGZxmQxFdCxWaiydFU0FXEwtdZKeqjimQi/5A976903e/de697917rJHFLM4jhjeWQ/RI0Z3P8ArKoJPv3XulLFsbe08AqoNn7pmpiuoVEW38tJAV+uoTJSGPTb839+690nJ6eopZDDUwTU8q/qinieGRbEg3SRVYcj+nv3XusPv3Xuve/de6c6nCZmioqXJVmIydJjq6/2VfU0FVBRVmn9X2tVLEkFRp/Ohjb3rr3WPHYrJ5ipWixGOr8pWMrOtJjqOorqlkQFnZYKaOWUqii5NrAe99e6izQzU0skFRFLBPC5jlhmjeKWJ1NmSSNwro6n6ggEe/de6xgX4HJPAA/Pv3XurRf5UHynwHwd+T0Xf2+Pj9u7urG02yNxbXwi7YpHXObOzWdlxwbdOENZQVGOqK04emqqB1Z4HFPXSFZByr1YVFK9a49WNfzHf+FBXcvyH6/ynSfQPWe6/jZs/c1JJjt87tz+WeXs3cGJqVljqdv4magocfS7QxORgbRVPDJUVk8d0WaKNnV9BQOPXqdaz/u/W+ve/de6cqXDZiupaquocVkqyhoQGrayloaqopaNWvpNVUQxPDThrG2si/v3Xum337r3S8x/VvZuWxozGK673zksQVLjKUG089WY9kAJLrWU9BJTsoA+oa3vXXukRNBNTSyQVEMtPPExSWGaN4pY3H1WSOQK6MP6EA+99e6xe/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r/1dev2/1fr3v3Xuve/de697917r3v3Xuve/de632v+E33w+/0J/EvM/IzdGM+3338mspBkcO9RAUq8f1PtWSrotpxIXJKx7jyk9dkyyWWamlpSblB7ac5p1U9DX/Od/mXZH4EUvxkw2yMgBvLe3b+C3dvXGQxwVNTU9H7MrYk3xizTTqVV91PkUpKeS6skkLsD6T78orXrwHV0W09z7f3/tHbu8dt1tLmtr7y2/i9xYTIQNHUUeTwmex8GQoKmNhqjlgqqKqVvyCD7r1rr5sn84v4gS/Dn5y9obTxOMeg647GrJO1+r3SJko125u6rqanIYalbxxxW23uJaujCJxHDHH/AF9uqajqw6qz92631sgf8JiP+y7OyP8AxXfdP/vZbH90fh1o9boPy/8A+yUfkr/4gjtf/wB4bOe6DiOq9fJ+9vdX6+rf8J/+yNvid/4rZ0f/AO+z2z7Y6oePRSfkZ/Ky6g+XPzf2d8o/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WNAetHh1/9LXr9v9X697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917reG/4TP8AwzyHWXSu/fl9vGhqaHPd7aNndeUtVDJA69YbZyYqa/NCOpx8Uph3RuqlHheKd4ZYMejFblSG3Pl1U9f/09ev2/1fr3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917qzD+V1/Lu3p/MG+QmD2cIq7B9N7Yq48v21vsUla9NRYWiQVbbaxU1MgV9xbhASnjLSQx0qzCSSRXaBJqk060T19K7YOxts9ZbJ2p17szF0uG2rsvAYvbeAxlHTUlHBS4zE0kVHTKKegp6SjSWRItchjiRXkZmsL+2uq9f//U16/b/V+ve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917q2r+XF/KF+RXz83PhM2cTlurPjwtcx3J3Pn8PULS19FRGkkr8b19QVQp13VnZ4qtEidWWhidmaSU+KRPdSwH29ar19Ar4n/ABM6Z+GnUOE6d6V2zSYPB45EqMxkxFfMbpzbIBVZvOV0jz1dXUzMT4xJLJ4kNtTMWdmya9V6Mx7117r/1dev2/1fr3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de697917r3v3Xuve/de6X2y+quz+yJxS9e9c7731UEsPDs/aWf3LINJ0uWXDUFYUVCfUTYL+be9de6tk+Pf8hD+Yx3pW0z53qqn6J221RjRWZ3uXIpt6thoa+eSKarpNp0S5Hc1XNQRwvJLBJT08gAUcF01aLAdar1sg/C/wD4TmfFToaoxe8vkPk6v5K7/otE0eHykD4PqnG1kZroxPDtiCT+I5/XFNBKq5Gpkihmi4jccmhY+XWq9bC2GwuG27jKPCbfxOMwWGx8ZhoMRhqClxeMoYmkeVoqOgoooKWmjaWRmKoigsxP1PuvWunP37r3Xvfuvdf/2Q==";
var logo_mimaos = "base64:,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//2Q==";


function addDirection(header_left)
{
	header_left.addBlock(
		"SUPERCONSUM SL\n"+
		"CL PINTOR SOROLLA 5\n"+
		"03610 PETRER\n"+
		"NIF: 9929293293\n"+
		"Tel: 9838383838 - Fax: 3333345555"
		)
		.setSpaceBefore("3.0cm")
		.setFontSize(8)
		.setFontWeight("bold")
		.setFontFamily("Helvetica")
		.setLinefeedTreatment("preserve");
}

function addIndentedDataTable(wrapper, rs)
{
	var container = wrapper.addBlockContainer().setWidth("11.0cm").setStartIndent("6.0cm");
	var table = container.addTable()
		.setFontSize(8)
		// Table automatically detects start-indent from parent container and resets to 0 if present
		//.setStartIndent("0cm")
		.setBorderStyle("solid")
		.setBorderWidth("0.25pt")
		.setSpaceBefore("10pt")
		.addResultSet(rs);
	
	table.getHeader().getRows().forEach(row => {
		row.forEach(cell => {
			cell.setTextAlign("center");
		});
		row.setBackgroundColor("#EAEAEA");
		}
	);
	
	table.getBody().getRows().forEach(row => {
		row.forEach(cell => {
			cell.setMargin("1pt");
			if (row.isLast()) {
				cell.setBorderTopStyle("solid");
				cell.setBorderTopWidth("1.0pt");
				cell.setFontWeight("bold");
			}
		});
		}
	);
	table.setFontSize(9);
}

function addLeftTable(fopBlockContainer)
{
	var t1 = fopBlockContainer.addTable();

	t1.setFontSize(9);

	t1.addColumns(
	   [
		"Farmacia",
		"Fecha Pedido",
		"Hora",
		"<center>Referencia</center>",
		"Albarán",
		"Fecha albarán",
		"Vencimiento"
	   ]
	).forEach(c => {
		c.getCell().setBackgroundColor("#EEEEEE");
		c.getCell().setFontWeight("bold");
		c.getCell().setPaddingTop(4);
		c.getCell().setPaddingLeft(5);
		c.getCell().setPaddingRight(5);
		c.getCell().setBorderStyle("solid");
		c.getCell().setBorderWidth(2);
		c.getCell().setBorderColor("white");
	});

	var r = t1.getBody().addRow([
				"MM-100353-C298182",
				"19-10-2017",
				"15:04",
				"42924",
				"1710-0416668",
				"19-10-2017",
				"20-11-17"
				]);
	r.forEach(c => {
		c.setPaddingBottom(4);
		c.setPaddingLeft(5);
		c.setPaddingRight(5);
		if (c.getColumnIndex() > 0) {
			c.setTextAlign("center");
			c.setBorderLeftStyle("solid");
			c.setBorderLeftWidth(4);
			c.setBorderLeftColor("red");
		}
	});

	// TODO: compute widths on non sized columns
	t1.pack();
}

function addRightTable(fopBlockContainer)
{
	var t1 = fopBlockContainer.addTable();
	
	t1.setFontSize(9);
	
	t1.addColumns([
		"Farmacia",
		"Fecha Pedido",
		"Hora",
		"Albarán"
	]).forEach(c => {
		c.getCell().setTextAlign("center");
		c.getCell().setBackgroundColor("#EEEEEE");
		c.getCell().setFontWeight("bold");
		c.getCell().setPaddingTop(4);
		c.getCell().setPaddingLeft(5);
		c.getCell().setPaddingRight(5);
		c.getCell().setBorderStyle("solid");
		c.getCell().setBorderWidth(2);
		c.getCell().setBorderColor("white");
		/*
		if (c.getColumnIndex() > 0) {
		c.getCell().setBorderLeftStyle("solid");
		c.getCell().setBorderLeftWidth(4);
		c.getCell().setBorderLeftColor("red");
		}
		*/
	});
	
	t1.getBody().addRow([
		"MM-100353-C298182",
		"19-10-2017",
		"15:04",
		"1710-0416668",
	]).forEach(c => {
		c.setPaddingBottom(4);
		c.setTextAlign("center");
		/*
		if (c.getColumnIndex() > 0) {
		c.setBorderLeftStyle("solid");
		c.setBorderLeftWidth(4);
		c.setBorderLeftColor("red");
		}
		*/
	});
	
	// TODO: compute widths on non sized columns
	t1.pack();
}

function addBodyTable(fopWrapper, width)
{
	var rs = getHeaderResultSet();
	
	// ==========================================================================
	// AUTOMATIC TABLE USING ResultSet table generator
	// ==========================================================================
	
	if (false) {
		var body = new ResultSet2FOP(rs, c => {
			c.setTableHeadAlign("left");
		}).getTableBody(width);
		fopWrapper.addFOPContent(body);
	}

	// ==========================================================================
	// MANUALLY SIZED TABLE
	// ==========================================================================
	var widths = [
		1.4, // codigo nacional
		5.4, // descripcion
		1.0, // caja
		1.9, // Ubicacion
		0.6, // CP
		0.6, // CS
		1.3, // CBonif
		1.2, // PVD
		1.3, // Importe Neto
		1.0, // IVA
		1.0, // PVP
		0.5, // CAB
		0.2, // - CENTER separator
		1.4, // Codigo nacional
		4.8, // Descripcion
		0.4, // O
		0.6, // CP
		0.6, // CS
		2.0, // CBonif
		0.5, // CAB
		0.5 // MAB
	];

	rs.beforeFirst();
	console.log("+++++ cell align should be as data!!");
	var table = fopWrapper.addBlock().addTable().addResultSet(rs);
	table.setBorderStyle("solid");
	table.setBorderWidth("0.5pt");
	table.setFontSize(7.5);
	table.forEach(column => {
		column.setColumnWidth(widths[column.getColumnIndex()]);
		switch (column.getColumnIndex()) {
			case 11:
			case 19:
			case 20:
				column.setAlign("center");
				break;
		}
	});
	table.getHeader().getRows().forEach(row => {
		row.setBackgroundColor("#EAEAEA");
		row.forEach(cell => {
			if (cell.getColumnIndex() == 12) {
				cell.setBackgroundColor("red");
			}
			cell.setFontWeight("bold");
			cell.setPadding("1pt");
			cell.setBorderStyle("solid");
		});
	});
	table.getBody().getRows().forEach(row => {
		row.forEach(cell => {
			if (cell.getColumnIndex() != 12) {
				cell.setPadding("1pt");
				cell.setBorderStyle("solid");
			}
		});
	});
}

function addOfertaDeLaSemana(fopWrapper)
{
	var rs = getOfertaDeLaSemana();
	var table = fopWrapper.addBlock().addTable()
	.setFontSize(8)
	.setBorderStyle("solid")
	.setBorderWidth("0.25pt")
	.setSpaceBefore("10pt")
	.addResultSet(rs);
	
	table.setCaption("OFERTA DE LA SEMANA").setMargin("1pt").setPadding("1pt").setBackgroundColor("#999999");
	
	table.forEach(column => {
		column.getCell().setMargin("1pt");
		column.getCell().setFontWeight("bold");
		switch (column.getColumnIndex()) {
			case 0: column.setColumnWidth(2.5); break;
			case 1: column.setColumnWidth(9.0); break;
			case 2: column.setColumnWidth(5.5); break;
		}
	});
	table.getHeader().getRows().forEach(row => {
		row.setBackgroundColor("#EAEAEA");
	});
	table.getBody().getRows().forEach(row => {
		row.forEach(cell => {
			cell.setMargin("1pt");
		});
	});
	table.setFontSize(9);
}

/**
*
*/
function createWaterMarkPDF()
{
	console.log("createWaterMarkPDF");
	var svg =
	"<svg:svg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'>                                              " +
	/*
	"<svg:rect x='0' y='0' width='1000' height='1000' fill='none' stroke='red' />                                                    " +
	"<svg:circle cx='100' cy='100' r='50' fill='none' stroke='black'/>                                                               " +
	"<svg:circle cx='220' cy='100' r='35' fill='red' stroke='black'/>                                                                " +
	"<svg:circle cx='340' cy='100' r='20' fill='black' stroke='lime' stroke-width='4'/>                                              " +
	"<svg:circle cx='100' cy='260' r='20' stroke='lime' fill='yellow' stroke-width='4'/>                                             " +
	"<svg:circle cx='220' cy='260' r='35' stroke='none' fill='blue'/>                                                                " +
	"<svg:circle cx='340' cy='260' r='50' stroke='red' fill='none' stroke-width='10'/>                                               " +
	*/
	"<svg:line x1='1' x2='1' y1='0' y2='1000' stroke='#000000' stroke-width='2' stroke-linecap='round' stroke-dasharray='1, 4'/>     " +
	"</svg:svg>";
	var root = new Ax.fop.FOPDocumentBuilder().createA4Document();
	root.rotate();
	root.getPageMaster().getRegionBody().setMargins(17.5, 0.0, 0.0, 0.0);
	root.getBodyFlow().addBlock().addInstreamForeignObject(svg).setContentHeight("20.0cm").setContentWidth("20.0cm");
	
		/* TODO
	fop2File(root, "watermark", true);
	*/
}

function getHeaderResultSet()
{
	var rows = [];
	rows.push([
		"0157170",
		"ANTISEPTICO DESINFECTOL 500 ML CON MUESTRA GRATIS",
		"644159",
		"037012051",
		1,
		1,
		null,
		4.88,
		4.88,
		21,
		null,
		null,
		// SEPARATOR
		null,
		// SECOND PART
		"0157170",
		"ANTISEPTICO DESINFECTOL 500 ML",
		"F",
		1,
		1,
		null,
		null,
		null,
		]
	);
rows.push([
		"067045",
		"SULFITO DE AMONIO BARRIL",
		"467321",
		"736278112",
		1,
		1,
		null,
		53.12,
		53.12,
		21,
		null,
		null,
		// SEPARATOR
		null,
		// SECOND PART
		"067045",
		"SULFITO DE AMONIO BARRIL",
		"",
		1,
		1,
		null,
		null,
		null,
		]
	);
	
	var rs = new Ax.rs.Reader().build(rows, options => {
		options.setColumnNames(
			[
			"Código\nNacional",
			"Descripción",
			"Caja",
			"Ubicac.",
			"CP",
			"CS",
			"CBonif\n/%DTO",
			"P.V.D",
			"Importe\nNeto",
			"%IVA",
			"P.V.P",
			"C\nAB",
			// SEPARATOR
			"-",
			// SECOND PART
			"Código\nNacional",
			"Descripción",
			"O",
			"CP",
			"CS",
			"CBonif/\n%Dto.",
			"C\nAB",
			"M\nAB"
			]
		);
		options.setColumnTypes(
			[
			Ax.sql.Types.CHAR,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.INTEGER,
			Ax.sql.Types.INTEGER,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.DOUBLE,
			Ax.sql.Types.DOUBLE,
			Ax.sql.Types.DOUBLE,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.CHAR,
			// SEPARATOR
			Ax.sql.Types.CHAR,
			// SECOND PART
			Ax.sql.Types.CHAR,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.INTEGER,
			Ax.sql.Types.INTEGER,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.CHAR,
			Ax.sql.Types.CHAR
			]
		);
	});
	return rs;
}

function getOfertaDeLaSemana()
{
	var rows = [
	[ "0179558", "GUANTE LATEX POLVO T/L      ", "DESDE 1 UNITS: -20% DT." ],
	[ "0179557", "GUANTE LATEX POLVO T/M      ", "DESDE 1 UNITS: -20% DT." ],
	[ "0179555", "GUANTE LATEX POLVO T/S      ", "DESDE 1 UNITS: -20% DT." ],
	[ "0183963", "GUANTE NITRILO SIN POLVO T L", "DESDE 1 UNITS: -20% DT." ],
	[ "0183961", "GUANTE NITRILO SIN POLVO T M", "DESDE 1 UNITS: -20% DT." ],
	[ "0183960", "GUANTE NITRILO SIN POLVO T S", "DESDE 1 UNITS: -20% DT." ],
	]
	var rs = new Ax.rs.Reader().build(rows, options => {
	options.setColumnNames(
	[
	"Código\nNacional",
	"Descripción",
	"Oferta"
	]);
	options.setColumnTypes(
	[
	Ax.sql.Types.CHAR,
	Ax.sql.Types.CHAR,
	Ax.sql.Types.CHAR
	]);
	});
	return rs;
}

function getTipologia()
{
	var rows = [
	[ "MINORISTA", 0, 0, 0 ],
	[ "GRAN VOLUMEN", 0, 0, 0 ],
	[ "PROD.QUIMICO", 4.59, -0.29, 4.88 ],
	[ "TOTAL", 4.59, -0.29, 4.88 ]
	];
	var rs = new Ax.rs.Reader().build(rows, options => {
	options.setColumnNames(
	[
	"TIPOLOGIA",
	"P.V.D",
	"DTO",
	"NETO"
	]);
	options.setColumnTypes(
	[
	Ax.sql.Types.CHAR,
	Ax.sql.Types.DECIMAL,
	Ax.sql.Types.DECIMAL,
	Ax.sql.Types.DECIMAL
	]);
	});
	return rs;
}

function getBasesImponibles()
{
	var rows = [
	["BASES\nIMPONIBLES", null, null, 4.88]
	];
	var rs = new Ax.rs.Reader().build(rows, options => {
	options.setColumnNames(
	[
	"",
	"I.V.A 4%",
	"I.V.A 10%",
	"I.V.A 21%"
	]);
	options.setColumnTypes(
	[
	Ax.sql.Types.CHAR,
	Ax.sql.Types.DECIMAL,
	Ax.sql.Types.DECIMAL,
	Ax.sql.Types.DECIMAL
	]);
	});
	return rs;
}

function getBarcode128(msg)
{
	//var svg = new Ax.barcode.SVG(msg).setPrintText(true).setHeight(1.25).toCode128();
	//var svg = new Ax.barcode.QrCode(msg).toSVG().replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "").replace("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">", "").replace(/[\r\n]+/g, "");
	var svg = new Ax.barcode.QrCode(msg).toSVG().replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "").replace("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">", "");
	console.log(svg);
	return svg;
}

//createWaterMarkPDF();

    var template = new Ax.fop.SinglePageTemplate("A4");

    // =======================================================================
    // CONFIGURE FOP ROOT LAYOUT
    // =======================================================================

    template.setRoot(root => {
        //root.setDebug("*");
        root.rotate();
        root.getSimplePageMaster().getRegionBefore().setExtent(6.5);
        root.getSimplePageMaster().getRegionAfter().setExtent(1.5);
        root.getSimplePageMaster().getRegionStart().setExtent(0);
        root.getSimplePageMaster().getRegionEnd().setExtent(0);
		root.getSimplePageMaster().setMargins(0.5, 0.5, 0.5, 0.5);
    });


    // =======================================================================
    // SET START & END VOID REGION CONTENT
    // =======================================================================
    template.setStart(start => {
        // VOID
    });
    template.setEnd(end => {
        // VOID
    });

    // =======================================================================
    // SET BEFORE REGION CONTENT
    // =======================================================================
    template.setBefore(before => {
// ===========================================================================
// Header
//
// [ALBARAN                             mimaos.png| |ALBRAN        mimaos.png]
// [
// [ Superfarma
// [ CL/PINTOR
// [ 020202 PETRER
// [ NIF: 339393
// [ Tel...
// [
// [ Farmacia Fecha pedido Hora Refencia..        | |Farmacia Fecha pedidos  ]
// [ MM-23333  19-10-2017
// ===========================================================================

var blockHeader   = before.addBlock();

var header_left   = blockHeader.addInlineContainer().setWidth("17.2cm");
var header_center = blockHeader.addInlineContainer().setWidth("0.8cm"); //.setBackgroundColor("#BBBBBB");
var header_right  = blockHeader.addInlineContainer().setWidth("10.8cm");

// ====================================================================
// Header LEFT
// ====================================================================
header_left.addBlockContainer()
			.setPosition("absolute")
			.setLeft("0.1cm")
			.addBlock()
			.addExternalGraphic(logo_albaran).setContentWidth("3.5cm");

header_left.addBlockContainer()
			.setPosition("absolute")
			.setLeft("13.0cm")
			.setWidth("4.2cm")
			.addBlock()
			.setTextAlign("right")
			.addExternalGraphic(logo_mimaos).setContentWidth("2.0cm");

addDirection(header_left);
header_left.addBlockContainer()
			.setPosition("absolute")
			.setTop("2.5cm")
			.setLeft("8.0cm")
			.addBlock()
			.addInstreamForeignObject(getBarcode128("1710-0416668 19-10-17 4,88 20-11-17")).setContentHeight(2.5);
addLeftTable(header_left.addBlockContainer()
			.setPosition("absolute")
			.setTop("5cm")
			.setLeft("0.0cm"));

// ====================================================================
// Header center
// ====================================================================
header_center.addBlockContainer().addBlock("."); // If not present, header_left and right disapears

header_center.addBlockContainer()
			.setWidth("0.2cm")
			.setHeight("19.0cm")
			.addBlock()
			//.addInstreamForeignObject(`<svg xmlns="http://www.w3.org/2000/svg" version="1.1" stroke="none"><path stroke-dasharray="5,5" d="M 0,0 V 8000" stroke="green" stroke-width="2" /></svg>`).setContentHeight("20.0cm"); //.setContentWidth("0.2cm")
			.addInstreamForeignObject(`<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="12px" height="1000px" viewBox="0 0 12 1000"><path stroke-dasharray="5,5" d="M 5,0 V 1000" stroke="green" stroke-width="1" /></svg>`).setContentHeight("20.0cm");
			//.addBlock(".");

// ====================================================================
// Header right
// ====================================================================
header_right.addBlockContainer()
			.setPosition("absolute")
			.setTop("0cm")
			.setLeft("18cm")
			.addBlock()
			.addExternalGraphic(logo_albaran).setContentWidth("3.5cm");

header_right.addBlockContainer()
			.setPosition("absolute")
			.setLeft("24.4cm")
			.setWidth("4.2cm")
			.addBlock()
			.setTextAlign("right")
			.addExternalGraphic(logo_mimaos).setContentWidth("2.0cm");

addDirection(header_right);
header_right.addBlockContainer()
			.setPosition("absolute")
			.setTop("2.5cm")
			.setLeft("25.0cm")
			.addBlock().addBlock().addInstreamForeignObject(getBarcode128("1710-0416668")).setContentHeight(2.5);
			addRightTable(header_right.addBlockContainer()
			.setPosition("absolute")
			// Don't know why width is need... but if not set, content is lost in thin width
			.setWidth("10.8cm")
			.setTop("5cm")
			.setLeft("17.8cm"));
});

// =======================================================================
// SET AFTER REGION CONTENT
// =======================================================================
template.setAfter(after => {
	var blockFooter   = after.addBlock();
	var footer_left   = blockFooter.addInlineContainer().setWidth("17.2cm");
	var footer_center = blockFooter.addInlineContainer().setWidth("0.4cm").setBackgroundColor("yellow");
	var footer_right  = blockFooter.addInlineContainer().setWidth("10.8cm"); //.setBackgroundColor("cyan");

	var totalPageNumbeId = after.getRoot().getPageSequence().getTotalPageNumberCitation();

	footer_left.addBlock(
	"TODA RECLAMACIÓN DEBERÁ EFECTUARSE DENTRO DE LOS DIEZ DÍAS SIGUIENTES A LA FECHA DEL ALBARÁN\n"+
	"Logística Avanzada de Transportes, S.L.U. - C/ Descubrimiento 7-13 Zona B3 Parque empresarial Pi-III 35120 Segovia C.I.F. Z12345044\n" +
	"Inscrita en el Registro Mercantil Segovia, Tomo 3138, Folio 15, Hoja 7649, Insc. 1"
	)
				.setFontSize(7)
				.setFontWeight("bold")
				.setFontFamily("Helvetica")
				.setLinefeedTreatment("preserve")
				.setTextAlign("center")
				.setBorderBottomWidth(.5)
				.setBorderBottomStyle("solid");
	footer_center.addBlock(" ");

	var table = footer_right.addTable().setFontSize(8);
	table.addColumn();
	table.addColumn();

	var row1 = table.getBody().addRow();
	var cell11 = row1.addCell().addBlock("Motivo Aono").setFontWeight("bold");
	var cell12 = row1.addCell().addBlock("COLUMNA O").setFontWeight("bold");
	var row2 = table.getBody().addRow();
	var cell21 = row2.addCell().addBlock("ME - MAL ESTADO FALTA GÉNERO\nNI - NO INTERESA").setLinefeedTreatment("preserve");
	var cell22 = row2.addCell().addBlock("CF = CLUB  T = OFERTA DIRECTA");

	var pagenumber = footer_right
							.addBlock()
							.setFontFamily("Helvetica")
							.setFontSize(8)
							.setTextAlign("end")
							.setPaddingTop(6);

	pagenumber.addInline()
			.addText("Page ")
			.putPageNumber()
			.addText(" - ")
			.putPageNumberCitation(totalPageNumbeId);

});

// =======================================================================
// SET BODY FLOW CONTENT
// =======================================================================
template.setBody(body => {
	addBodyTable(body.getWrapper(), 28.5);
	addOfertaDeLaSemana(body.getWrapper());
	addIndentedDataTable(body.getWrapper(), getTipologia());
	addIndentedDataTable(body.getWrapper(), getBasesImponibles());
});

// =======================================================================
// SET BODY FOOT NOTE CONTENT
// =======================================================================
template.setBodyFootNote(footnote => {
    // TODO
});

// ====================================================================
// GENERATE PDF
// ====================================================================
var fop = template.toFOP();
console.log(fop);

// ====================================================================
// WaterMark
// ====================================================================
//byte[] temp = fop2byte(root, "companybg", true);

//WaterWark wm = new WaterWark(temp, Overlay.Position.FOREGROUND);
//wm.setOverlay("/tmp/watermark.pdf", Pages.ALL);

var pdf = new Ax.fop.Processor().transform(fop);

return pdf;
Click here to download the PDF example

7 Atomic examples

This section shows some atomic micro-examples showing advanced fop generation functionality.

7.1 Dynamic row styles

This example, uses getCells() method to obtain a list of all cells containe in a FOP Table Row.

Copy
var template = new Ax.fop.SinglePageTemplate("A4");
template.setBody(body => { var table_cond = body.addTable();
    table_cond.setSpaceBefore("20pt"); table_cond.setBorderColor("black").setBorderStyle("solid");
    table_cond.addColumn("Referencia de pedido").setColumnWidth(6).setAlign("center");
    table_cond.addColumn("Fecha de pedido").setColumnWidth(6).setAlign("center");
    table_cond.addColumn("Transportista").setColumnWidth(7).setAlign("center");

    table_cond.getHeader().getRows().forEach(row => {
        row.setBackgroundColor("#CCCCCC");
    });
    table_cond.getHeader().getColumns().forEach(col => {
        col.getCell().setFontWeight("bold");
    });

    var row_cond = table_cond.getBody().addRow("REFTER1", "01-01-2021", "TRANSPORT");
    var row_cond = table_cond.getBody().addRow("REFTER2", "04-01-2021", "ALTERNATE");
    var row_cond = table_cond.getBody().addRow("REFTER3", "06-01-2021", "TRANS_R3");
    var row_cond = table_cond.getBody().addRow("REFTER4", "07-01-2021", "R4 TRANS");
    rpos=0; table_cond.getBody().getRows().forEach(row => {
    if (++rpos % 2 == 0) { row.setBackgroundColor("yellow"); 
        row.getCells().forEach(col => {
            col.setFontWeight("bold");
        });
    }
    });
});
var fop = template.toFOP();let pdf = new Ax.fop.Processor().transform(fop);
return pdf;

7.2 FOP Block Container

fo:block-container is a container of blocks. Into a table cell, setting overflow property to hidden allows to hidde the text overflowing cell size.

Copy
// Implement block-container and allow to set overflow property
// Documentation: https://www.w3.org/2002/08/XSLFOsummary.html#block
// Other docs: http://www.datypic.com/sc/fo11/e-fo_block-container.html

var template = new Ax.fop.SinglePageTemplate("A4");

template.setBody(body => {
    var table = body.addTable();

    table.setSpaceBefore("20pt");
    table.addColumn().setColumnWidth(1);
    table.addColumn().setColumnWidth(1);

    var row1 = table.getBody().addRow();
    var c11 = row1.addCell();
    var c12 = row1.addCell();
 
    c11.addBlockContainer().setOverflow("hidden").addBlock("Iamtoowideforacell");
    c12.addBlockContainer().setOverflow("hidden").addBlock("Iamtoowideforacell");
});

var fop = template.toFOP();
console.log(fop);
let pdf = new Ax.fop.Processor().transform(fop);

return pdf;

7.3 FOP Inline Container

In FO, fo:block is similar to HTML <div> and fo:inline-container is similar to HTML <span>

In this example you define two diferent inline blocks that are rendered in the same line, one beside the other.

Copy
var template = new Ax.fop.SinglePageTemplate("A4");
template.setBody(body => {
    var blk = body.addBlock().setFontSize(0);
    var ic1 = blk.addInlineContainer().setInlineProgressionDimension("80mm");
    var ic2 = blk.addInlineContainer().setInlineProgressionDimension("130mm");

    ic1.addBlock("Text left").setTextAlign("left").setFontSize(10).setBackgroundColor("red");
    ic2.addBlock("Text right").setTextAlign("right").setFontSize(10).setBackgroundColor("yellow");
});

var fop = template.toFOP();
console.log(fop);
let pdf = new Ax.fop.Processor().transform(fop);

return pdf;

7.4 Preserve white spaces in Block

Copy
var template = new Ax.fop.SinglePageTemplate("A4");

template.setRoot(root => {
    root.getSimplePageMaster().getRegionBefore().setExtent(2.5);
    root.getSimplePageMaster().getRegionAfter().setExtent(1.5);
    root.getSimplePageMaster().setMargins(1, 1, 1, 1);
});

template.setBody(body => {
    // white-space=pre preserves spaces and new lines
    pre = body.createBlockProperties();
    pre.setProperty("white-space", "pre"); 
    
    // preserve spaces and convert new line to space
    spc = body.createBlockProperties();
    spc.setProperty("white-space-treatment", "preserve"); 
    spc.setProperty("white-space-collapse",  "false");

    bcbody = body.addBlockContainer();
    bcbody.setBorderLeftStyle("solid").setBorderLeftColor("black");

    bcbody.addBlock(`    HOLA-1      *`).setProperties(pre);
    bcbody.addBlock(`
    HOLA-2      *
    `).setProperties(pre);
    bcbody.addBlock(`    HOLA-3      *`).setProperties(spc);
    bcbody.addBlock(`
    HOLA-4      *
    `).setProperties(spc);
});

var fop = template.toFOP();
console.log(fop);
let pdf = new Ax.fop.Processor().transform(fop);
return pdf;