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.
<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.
<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.
<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.
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;

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.
// ==================================================================== // 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.
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("© 2020 deister software"); }); // ======================================================================= // CONFIGURE END // ======================================================================= template.setEnd(end => { end.addBlock().setPaddingTop("10pt").setFontFamily(FONT_NAME).setFontSize(8).setTextAlign("center") .addTextLiteral("© 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>

6.2 Invoice 2 example
Same as before with style variations
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("© 2020 deister software"); }); // ======================================================================= // CONFIGURE END // ======================================================================= template.setEnd(end => { end.addBlock().setPaddingTop("10pt").setFontFamily(FONT_NAME).setFontSize(8).setTextAlign("center") .addTextLiteral("© 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);

6.3 Invoice 3 example
Same as before with style variations
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("· "+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);

6.4 Invoice 4 example
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
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;

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.
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.
// 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.
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
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;