Generating PDF files from HTML with inserted business data (integrated with DocRaptor)

DocRaptor is a web service that converts source HTML data received via API into PDF format and returns it as a PDF file.

This article explains the basic use of the built-in automatic step [DocRaptor: Generate PDF].

A similar automatic step for generating PDF files, [Adobe: PDF Generation (HTML to PDF)], which accesses the Adobe Acrobat Service API, is also available.

Preparation for DocRaptor

Get an account on the DocRaptor website. After signing up with your email address, name and password, an API Key will be issued and displayed on the Document History page, so make a note of it.

DocRaptor free plan accounts have a limit of five documents per month, but in TEST mode you can create an unlimited number of documents, subject to DocRaptor’s watermarking. When a [DocRaptor: Generate PDF] automatic step is debugged in a workflow app in Questetra, it works as TEST mode in DocRaptor.

Configuring [DocRaptor: Generate PDF] step

[DocRaptor: Generate PDF] automated steps work in the following steps:

  1. Access the DocRaptor’s API.
  2. Send the specified HTML data.
  3. Download and save the PDF file generated by DocRaptor based on the sent data.
[DocRaptor: Generate PDF] automatic steps are set up with the following items corresponding to the above steps.

  1. The HTTP authentication setting for accessing DocRaptor’s API
  2. The data item for storing the HTML data of the conversion source to be sent to the API
  3. The data item to store the downloaded PDF file

HTTP authentication settings

Open the settings screen of a [DocRaptor: Generate PDF] step, and click [Set up Setting] to go to the [HTTP Authorization Setting] screen. Move to [Basic Authentication] in the tabs at the top and click [+ Add] under [Workflow app specific settings] to open the screen to set up a new Basic Authentication setting.

In [Name], enter a string to identify the individual settings (e.g. DocRaptor-USERNAME), in [Username] enter the API key obtained from DocRaptor, and [Save]. (Leave [Password] blank).

Select the [Name] for the HTTP Authentication setting specified above in [C1: BASIC Authentication Setting in which API key is set as Username] in the [DocRaptor: Generate PDF] settings screen. (If it does not appear, reload the screen.)

Although only the API key is specified, the setting should be created using the [Basic authentication] type instead of [Token Fixed Value].

Data item to save the source HTML as the conversion source

Specify the data item in [C2: Data item that stores the source HTML]. You can specify either a String-type (multiple lines) or a File-type data item. The source HTML is stored in the target data item in the input step.

What is source HTML?

HTML (Hyper Text Markup Language) is a markup language for displaying web pages in web browsers such as Chrome and Edge. In this article, the HTML data from which a PDF is converted is referred to as “source HTML”. Source HTML contains information on the formatting of pages, such as the arrangement and style of strings, in addition to the information on the character strings displayed in a PDF.

In Questetra, there is a function to automatically send emails written in HTML in a workflow, please refer to the following page for a further explanation about HTML.
Tutorial:  Let’s Send Mail Automatically in the Middle of a Workflow (HTML Mail chapter)

Data item to save the PDF file

Specify a File-type data item in [C3: Data item to save the generated PDF file].

Input a string ending in “.pdf” as the file extension in [C5: File name to save as] to specify the file name when the file is saved. An EL expression can be specified instead of a string.

Prepare the source HTML in which the business data will be inserted.

If you use an HTML code with EL expressions referring to data items as the source HTML, you can generate a PDF file in which business data has automatically been inserted. This section describes how to insert the values of data items into HTML code using EL expressions.

First, prepare HTML code with a format, such as fixed strings and their placement. Next, in the HTML, write an EL expression that refers to the data item or the system variable in the place where you want to insert the value of it.

Reference: R2272: Output of Strings via EL syntax

A detailed example of preparing the source HTML is given later in this article.

Sample app

A sample app for DocRaptor

Create an app to check how [DocRaptor: Generate PDF] actually works. This app uses an automatic step, [Generate Text File], to generate an HTML file, which is then set as the source HTML to convert to PDF.

It is very hard to write format definitions in HTML from scratch, so here you will prepare the source HTML using the template provided by DocRaptor. Download the A4 size template file for invoices (invoice.A4.html) from the following website.

Templates page of DocRaptor: Free HTML to PDF Templates
Direct download: invoice.A4.html (Save the linked html file.)

Workflow App Settings

Data Items

The data items required to run [DocRaptor: Generate PDF] include one that stores the source HTML and the one that stores the generated PDF file. If you want to use the source HTML containing the values of data items to convert the PDF file, prepare the data items for the inserted values.

Data Item NameData TypeField NameRequiredEnter Billing Information stepDescription
TitleEditableProcess Title.
HTML FileFile-typeq_htmlNo DisplaStores the source HTML.
PDF FileFile-typeq_pdfNo DisplayStores the generated PDF file.
The following are the data items to be inserted into the template
Billing nameString-type (single line)q_billing_nameEditable
Billing addressString-type (multiple lines)q_billing_addressEditable
Billing email addressString-type (multiple lines)q_billing_emailEditable
Payment due dateDate-type (Y/M/D)q_due_dateEditableInitial Value: #today.addDays(30)
Item name 1 String-type (single line)q_item_name1Editable
Remark 1String-type (single line)q_remark1Editable
Unit price 1Numeric-typeq_unit1Editable
Quantity 1Numeric-typeq_quantity1Editable
Price 1Numeric-typeq_price1EditableExpression: #q_unit1 * #q_quantity1
Item name 2 String-type (single line)q_item_name2Editable
Remark 2String-type (single line)q_remark2Editable
Unit price 2Numeric-typeq_unit2Editable
Quantity 2Numeric-typeq_quantity2Editable
Price 2Numeric-typeq_price2EditableExpression: #q_unit2 * #q_quantity2
Item name 3 String-type (single line)q_item_name3Editable
Remark 3String-type (single line)q_remark3Editable
Unit price 3Numeric-typeq_unit3Editable
Quantity 3Numeric-typeq_quantity3Editable
Price 3Numeric-typeq_price3EditableExpression: #q_unit3 * #q_quantity3
SubtotalNumeric-typeq_subtotalEditableExpression: #q_price1 + #q_price2 + #q_price3
TaxNumeric-typeq_taxEditableExpression: #q_subtotal * 0.1
Total amountNumeric-typeq_totalEditableExpression: #q_subtotal + #q_tax
Issue dateDate-type (Y/M/D)q_issue_dateEditableInitial Value: #today
Invoice IDString-type (single line)q_invoice_idEditableInitial Value: #{processInstanceSequenceNumber}
Data Item Settings

“Generate HTML File” (Generate Text File) step

This step generates an HTML file which is the source HTML for the “Generate PDF File” step: the HTML in which the values of the data items have been inserted by EL expressions is output as an HTML file. 

Note that the output destination file specified in [C1: File-type data item to save text file] here should be selected in [C2: Data item that stores the source HTML] in the “Generate PDF File” step.

Item NameRequiredDescription
C1: File-type data item to save text fileSpecify the Data Item “HTML File” here.
C2: Delete other files when saving
C3: Saving file nameUse an automatically numbered variable, e.g. source-#{processInstanceId}.html (the file extension “.html” is mandatory.)
C4: Contents of text fileInput the code that becomes the source HTML.(HTML code with data reference expressions (EL expressions) inserted into the prepared one that defines the format)
C5: Character encoding when saving (UTF-8 if not selected)Select UTF-8 (can also be left blank.)
C6: File type when saving (text/plain if not selected)Select text/html.
“Generate HTML File” (Generate Text File) step Settings

“Generate PDF File” (DocRaptor: Generate PDF) step

Specify the data items included the HTTP Authentication settings for accessing DocRaptor, the item stores the source HTML code for the PDF and the items to save the generated PDF file.

Item NameRequiredDescription
C1: Basic Auth Setting in which API Key is set as UsernameSpecifies the HTTP authentication settings used to connect to DocRaptor. The authentication settings to be specified must be created in advance. (See “HTTP authentication settings” above).
C2: Data item that stores the source HTMLSpecify the data item for which the original source HTML of the PDF is to be rated (“HTML File” in this case).
C3: Data item to save the generated PDF fileSpecifies the File-type data item to store the generated PDF (“PDF File” in this case).
C4: Delete other files when saving
C5: File name to save asUse automatically numbered variables such as #{processInstanceId}.pdf (file extension “.pdf” is mandatory).
“Generate PDF File” (DocRaptor: Generate PDF) Settings

Edit the template and run [DocRaptor: Generate PDF].

Create the source HTML from the downloaded template (invoice.A4.html) proceeding in the following steps.

  1. Edit the template to insert business data.
  2. Check the results of the edits in the PDF created in the [DocRaptor: Generate PDF] step.

In practice, you will proceed by repeatedly editing parts of the template code and checking the generated PDF. The number of PDFs that can be generated is limited by each DocRaptor subscription plan, so run this application in debug mode to prevent the number of generated PDFs from being counted. The following operations are carried out in the Edit mode of the application editor.

Checking the downloaded template

First, check what the downloaded template looks like.

Run [Debug only this node] from the configuration screen of the “Generate PDF” (DocRaptor: Generate PDF) step. In the “Input test data” step of the debugging process that has been started, [Add…] the downloaded invoice.A4.html to [HTML File] and click [Finish “Input test data”] to proceed.

After the debugging process is completed, check the PDF file saved in the “PDF File”.

File-type data items in the debugging process
PDF generated from the downloaded template

Edit the HTML code set in [Generate Text File]

Take a look at the generated PDF file. In this PDF, the client name, email address, etc., are temporary strings; rewrite the HTML code and modify the parts that need to be changed.

The areas surrounded by green rectangles in the screenshot above are fixed strings that are common to all invoices, e.g. your company name. Replace them with the appropriate text. The areas surrounded by red rectangles are areas that vary from invoice to invoice. These should be filled in with the values of the data items.

Rewriting fixed strings

Now, edit and rewrite the downloaded invoice.A4.html. Open the file in a text editor (e.g. Notepad application) and you will see the code, which is the source HTML. After making changes to the code in the text editor, copy and paste the entire code into [C4: Contents of text file] of the “Generate HTML File” (Generate Text File) step. When the ”Generate HTML File” step is carried out, an HTML file is generated reflecting the changes.

In the code shown, the actual content, e.g. text, that appears in the PDF is described after <header>. Let’s rewrite the text that appears as “Logo & Name” in the PDF.

The part from the beginning to about two-thirds of the code is a style sheet to specify the appearance of the text (<style> to </style>). 

    <div class="logoAndName">
      <svg>
        <circle cx="50%" cy="50%" r="40%" stroke="black" stroke-width="3" fill="black" />
      </svg>
      <h1>Logo & Name</h1>
    </div>
    <!-- Details about the invoice are on the right top side of each page. -->
    <div class="invoiceDetails">
      <h2>Invoice #100</h2>
      <p>
        07 March 2021
      </p>
    </div>

Replace <h1>Logo &amp; Name</h1> with the company name (Questetra). Also remove <svg>~</svg> (displaying the logo).

  <div class="logoAndName">
      <h1>Questetra</h1>
    </div>
    <!-- Details about the invoice are on the right top side of each page. -->
    <div class="invoiceDetails">
      <h2>Invoice #100</h2>
      <p>
        07 March 2021
      </p>
    </div>
Data insertion Rewritten with EL expression

Next, rewrite this part with EL expressions that insert values that refer to data items. In the code above, the “#100” part contains an expression that refers to the data item “Invoice ID” and the “07 March 2021” part refers to the “Issue Date”.

<div class="logoAndName">
      <h1>Questetra</h1>
    </div>
    <!-- Details about the invoice are on the right top side of each page. -->
    <div class="invoiceDetails">
      <h2>Invoice ##{#q_invoice_id}</h2>
      <p>
        #{#q_issue_date}
      </p>
    </div>

EL expressions that refer to data are written in the basic #{#field name} format, but it is also possible to change the output format using functions. For example, let’s look at the “Billing address {String-type (multi-lines)}” to be inserted in “Invoice to” or the “Payment due date (date type YMD)” to be inserted in “Due Date”.

    <div>
      <h3>Invoice to</h3>
      <p>
        <b>#{#q_billing_name}</b>
        <br />
        #{#joiner.splitJoin(#q_billing_address, '<br>')}
        <br />
        <a href="mailto:#{#q_billing_email}">
          #{#q_billing_email}
        </a>
      </p>
    </div>
    <!-- Additional details can be placed below the invoice details. -->
    <div>
      <h3>Due Date</h3>
      <p>
        <b>#{#dateFormatter.format('dd MM yyyy', #q_due_date)}</b>
      </p>
    </div>

If entering #{#q_billing_address} as it is to insert the value stored in a String-type (multiple lines) data item, the strings will not be broken in HTML and will be displayed on a single line. Write a function that inserts a <br>for each line to keep the multiple lines.

#{#joiner.splitJoin(#q_billing_address, '<br>')}

R2272: Output of Strings via EL syntax (data setting expression)

After rewriting the code, copy and paste the entire code into [C4: Contents of text file] in the “Generate HTML File” (Generate Text File) step.

Process the “Enter Data” step using [Start debug process] from the start event of the app. Check the generated PDF file on the detail screen of the finished debug process.

When the changes have been made correctly, edit the next section and check the result,  and repeat to complete the overall editing process. See also the entire HTML code edited for this article.

Code edited in its entirety: HTML code sample

Checking the performance

Once all the parts of invoice.A4.html that need to be edited have been modified, carry out operational checks using [Debug execution] in the start event. Check that the values entered in the “Data input” process are inserted into the PDF file generated in the “PDF generation” step. If the PDF is not generated as expected, review the content of the HTML set in [C4: Text file content] in the [Generate HTML File] step.

As described above, by preparing the source HTML to insert business data using the EL expression, a PDF file with inserted business data can be generated.

Appendix

Prepare as a PDF generation sub-process

PDF files with a specific format, such as invoices issued in a common format for each department in the company, may be generated by multiple operations (apps). In such cases, instead of placing a PDF generation step in each business application, consider turning a series of PDF generation processes into sub-processes.

If “PDF generation” is defined as a sub-process in an independent app, it is easy to integrate the “PDF generation” operation by passing data to this app. Also, if you want to change the format of the generated PDF, you do not need to make the change in each individual business app, but only need to change one part of the sub-process, which increases maintainability.

For more information on sub-processes, see the following article.

Linking and Operating Multiple Workflow Apps – Automated Sub-Processes

HTML code sample

The full HTML code that has been modified in this article based on the template downloaded from DocRaptor (invoice.A4.html) is shown below. (Click to open)

HTML code with EL expressions (full text)
<!--
The following is the license for the original template file.
------------------------------------
MIT License

Copyright (c) 2021 Expected Behavior, LLC

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------
-->
<style>
  /* 
  Import the desired font from Google fonts. 
  */
  @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&display=swap');
  
  /* 
  Define all colors used in this template 
  */
  :root{
    --font-color: black;
    --highlight-color: #60D0E4;
    --header-bg-color: #B8E6F1;
    --footer-bg-color: #BFC0C3;
    --table-row-separator-color: #BFC0C3;
  }
  
  @page{
    /*
    This CSS highlights how page sizes, margins, and margin boxes are set.
    https://docraptor.com/documentation/article/1067959-size-dimensions-orientation
  
    Within the page margin boxes content from running elements is used instead of a 
    standard content string. The name which is passed in the element() function can
    be found in the CSS code below in a position property and is defined there by 
    the running() function.
    */
    size:A4;
    margin:8cm 0 3cm 0;
  
    @top-left{
      content:element(header);
    }
  
    @bottom-left{
      content:element(footer);
    }
  }
  
  /* 
  The body itself has no margin but a padding top & bottom 1cm and left & right 2cm.
  Additionally the default font family, size and color for the document is defined
  here.
  */
  body{
    margin:0;
    padding:1cm 2cm;
    color:var(--font-color);
    font-family: 'Montserrat', sans-serif;
    font-size:10pt;
  }
  
  /*
  The links in the document should not be highlighted by an different color and underline
  instead we use the color value inherit to get the current texts color.
  */
  a{
    color:inherit;
    text-decoration:none;
  }
  
  /*
  For the dividers in the document we use an HR element with a margin top and bottom 
  of 1cm, no height and only a border top of one millimeter.
  */
  hr{
    margin:1cm 0;
    height:0;
    border:0;
    border-top:1mm solid var(--highlight-color);
  }
  
  /*
  The page header in our document uses the HTML HEADER element, we define a height 
  of 8cm matching the margin top of the page (see @page rule) and a padding left
  and right of 2cm. We did not give the page itself a margin of 2cm to ensure that
  the background color goes to the edges of the document.
  
  As mentioned above in the comment for the @page the position property with the 
  value running(header) makes this HTML element float into the top left page margin
  box. This page margin box repeats on every page in case we would have a multi-page
  invoice.
  */
  header{
    height:8cm;
    padding:0 2cm;
    position:running(header);
    background-color:var(--header-bg-color);
  }
  
  /*
  For the different sections in the header we use some flexbox and keep space between
  with the justify-content property.
  */
  header .headerSection{
    display:flex;
    justify-content:space-between;
  }
  
  /*
  To move the first sections a little down and have more space between the top of 
  the document and the logo/company name we give the section a padding top of 5mm.
  */
  header .headerSection:first-child{
    padding-top:.5cm;
  }
  
  /*
  Similar we keep some space at the bottom of the header with the padding-bottom
  property.
  */
  header .headerSection:last-child{
    padding-bottom:.5cm;
  }
  
  /*
  Within the header sections we have defined two DIV elements, and the last one in
  each headerSection element should only take 35% of the headers width.
  */
  header .headerSection div:last-child{
    width:35%;
  }
  
  /*
  For the logo, where we use an SVG image and the company text we also use flexbox
  to align them correctly.
  */
  header .logoAndName{
    display:flex;
    align-items:center;
    justify-content:space-between;
  }
  
  /*
  The SVG gets set to a fixed size and get 5mm margin right to keep some distance
  to the company name.
  */
  header .logoAndName svg{
    width:1.5cm;
    height:1.5cm;
    margin-right:.5cm;
  }
  
  /*
  To ensure the top right section "Invoice #100" starts on the same level as the Logo &
  Name we set a padding top of 1cm for this element.
  */
  header .headerSection .invoiceDetails{
    padding-top:.5cm;
  }
  
  /*
  The H3 element "ISSUED TO" gets another 25mm margin to the right to keep some 
  space between this header and the client's address.
  Additionally this header text gets the hightlight color as font color.
  */
  header .headerSection h3{
    margin:0 .75cm 0 0;
    color:var(--highlight-color);
  }
  
  /*
  Put some margin between the "DUE DATE" and "AMOUNT" headings.
  */
  header .headerSection div:last-of-type h3:last-of-type{
    margin-top:.5cm;
  }
  
  /*
  The paragraphs within the header sections DIV elements get a small 2px margin top
  to ensure its in line with the "ISSUED TO" header text.
  */
  header .headerSection div p{
    margin-top:2px;
  }
  
  /*
  All header elements and paragraphs within the HTML HEADER tag get a margin of 0.
  */
  header h1,
  header h2,
  header h3,
  header p{
    margin:0;
  }
  
  /*
  The invoice details should not be uppercase and also be aligned to the right.
  */
  header .invoiceDetails,
  header .invoiceDetails h2{
    text-align:right;
    font-size:1em;
    text-transform:none;
  }
  
  /*
  Heading of level 2 and 3 ("DUE DATE", "AMOUNT" and "INVOICE TO") need to be written in 
  uppercase, so we use the text-transform property for that.
  */
  header h2,
  header h3{
    text-transform:uppercase;
  }
  
  /*
  The divider in the HEADER element gets a slightly different margin than the 
  standard dividers.
  */
  header hr{
    margin:1cm 0 .5cm 0;
  }
  
  /*
  Our main content is all within the HTML MAIN element. In this template this are
  two tables. The one which lists all items and the table which shows us the 
  subtotal, tax and total amount.
  
  Both tables get the full width and collapse the border.
  */
  main table{
    width:100%;
    border-collapse:collapse;
  }
  
  /*
  We put the first tables headers in a THEAD element, this way they repeat on the
  next page if our table overflows to multiple pages.
  
  The text color gets set to the highlight color.
  */
  main table thead th{
    height:1cm;
    color:var(--highlight-color);
  }
  
  /*
  For the last three columns we set a fixed width of 2.5cm, so if we would change
  the documents size only the first column with the item name and description grows.
  */
  main table thead th:nth-of-type(2),
  main table thead th:nth-of-type(3),
  main table thead th:last-of-type{
    width:2.5cm;
  }
  
  /*
  The items itself are all with the TBODY element, each cell gets a padding top
  and bottom of 2mm.
  */
  main table tbody td{
    padding:2mm 0;
  }
  
  /*
  The cells in the last column (in this template the column containing the total)
  get a text align right so the text is at the end of the table.
  */
  main table thead th:last-of-type,
  main table tbody td:last-of-type{
    text-align:right;
  }
  
  /*
  By default text within TH elements is aligned in the center, we do not want that
  so we overwrite it with an left alignment.
  */
  main table th{
    text-align:left;
  }
  
  /*
  The summary table, so the table containing the subtotal, tax and total amount 
  gets a width of 40% + 2cm. The plus 2cm is added because our body has a 2cm padding
  but we want our highlight color for the total row to go to the edge of the document.
  
  To move the table to the right side we simply set a margin-left of 60%.
  */
  main table.summary{
    width:calc(40% + 2cm);
    margin-left:60%;
    margin-top:.5cm;
  }
  
  /*
  The row containing the total amount gets its background color set to the highlight 
  color and the font weight to bold.
  */
  main table.summary tr.total{
    font-weight:bold;
    background-color:var(--highlight-color);
  }
  
  /*
  The TH elements of the summary table are not on top but the cells on the left side
  these get a padding left of 1cm to give the highlight color some space.
  */
  main table.summary th{
    padding:4mm 0 4mm 1cm;
  }
  
  /*
  As only the highlight background color should go to the edge of the document
  but the text should still have the 2cm distance, we set the padding right to 
  2cm.
  */
  main table.summary td{
    padding:4mm 2cm 4mm 0;
    border-bottom:0;
  }
  
  /*
  The content below the tables is placed in a ASIDE element next to the MAIN element.
  To ensure this element is always at the bottom of the page, just above the page 
  footer, we use the Prince custom property "-prince-float" with the value bottom.
  
  See Page Floats on https://www.princexml.com/howcome/2021/guides/float/.
  */
  aside{
    -prince-float: bottom;
    padding:0 2cm .5cm 2cm;
  }
  
  /*
  The content itself is shown in 2 columns we use flexbox for this.
  */
  aside > div{
    display:flex;
    justify-content:space-between;
  }
  
  /*
  Each "column" has a width of 45% of the document.
  */
  aside > div > div{
    width:45%;
  }
  
  /*
  The list with the payment options has no bullet points and no margin.
  */
  aside > div > div ul{
    list-style-type:none;
    margin:0;
  }
  
  /*
  The page footer in our document uses the HTML FOOTER element, we define a height 
  of 3cm matching the margin bottom of the page (see @page rule) and a padding left
  and right of 2cm. We did not give the page itself a margin of 2cm to ensure that
  the background color goes to the edges of the document.
  
  As mentioned above in the comment for the @page the position property with the 
  value running(footer) makes this HTML element float into the bottom left page margin
  box. This page margin box repeats on every page in case we would have a multi-page
  invoice.
  
  The content inside the footer is aligned with the help of line-height 3cm and a 
  flexbox for the child elements.
  */
  footer{
    height:3cm;
    line-height:3cm;
    padding:0 2cm;
    position:running(footer);
    background-color:var(--footer-bg-color);
    font-size:8pt;
    display:flex;
    align-items:baseline;
    justify-content:space-between;
  }
  
  /*
  The first link in the footer, which points to the company website is highlighted 
  in bold.
  */
  footer a:first-child{
    font-weight:bold;
  }
</style>

<!-- The header element will appear on the top of each page of this invoice document. -->
<header>
  <div class="headerSection">
    <!-- As a logo we take an SVG element and add the name in an standard H1 element behind it. -->
    <div class="logoAndName">
      <h1>Questetra</h1>
    </div>
    <!-- Details about the invoice are on the right top side of each page. -->
    <div class="invoiceDetails">
      <h2>Invoice ##{#q_invoice_id}</h2>
      <p>
        #{#q_issue_date}
      </p>
    </div>
  </div>
  <!-- The two header rows are divided by an blue line, we use the HR element for this. -->
  <hr />
  <div class="headerSection">
    <!-- The clients details come on the left side below the logo and company name. -->
    <div>
      <h3>INVOICE TO</h3>
      <p>
        <b>#{#q_billing_name}</b>
        <br />
        #{#joiner.splitJoin(#q_billing_address, '<br>')}
        <br />
        <a href="mailto:#{#q_billing_email}">
          #{#q_billing_email}
        </a>
      </p>
    </div>
    <!-- Additional details can be placed below the invoice details. -->
    <div>
      <h3>DUE DATE</h3>
      <p>
        <b>#{#dateFormatter.format('dd MM yyyy', #q_due_date)}</b>
      </p>
      <h3>AMOUNT</h3>
      <p>
        <b>¥#{#q_total}</b>
      </p>
    </div>
  </div>
</header>

<!-- The footer contains the company's website and address. To align the address details we will use flexbox in the CSS style. -->
<footer>
    <a href="https://questetra.com">
      questetra.com
    </a>
    <a href="mailto:customer-sevice@questetra.com">
      customer-sevice@questetra.com
    </a>
    <span>
      206 Takamiya-cho Oike Bldg. 4th Fl. Nakagyo-ku Kyoto 604-0835 JAPAN
    </span>
</footer>

<!-- In the main section the table for the separate items is added. Also we add another table for the summary, so subtotal, tax and total amount. -->
<main>
  <table>
    <!-- A THEAD element is used to ensure the header of the table is repeated if it consumes more than one page. -->
    <thead>
      <tr>
        <th>Item Description</th>
        <th>Rate</th>
        <th>Amount</th>
        <th>Total</th>
      </tr>
    </thead>
    <!-- The single invoice items are all within the TBODY of the table. -->
    <tbody>
      <tr>
        <td>
          <b>#{#q_item_name1}</b>
          <br />
          #{#q_remark1}
        </td>
        <td>
          #{#q_unit1}
        </td>
        <td>
          #{#q_quantity1}
        </td>
        <td>
          #{#q_price1}
        </td>
      </tr>
      <tr>
        <td>
          <b>#{#q_item_name2}</b>
          <br />
          #{#q_remark2}
        </td>
        <td>
          #{#q_unit2}
        </td>
        <td>
          #{#q_quantity2}
        </td>
        <td>
          #{#q_price2}
        </td>
      </tr>
      <tr>
        <td>
          <b>#{#q_item_name3}</b>
          <br />
          #{#q_remark3}
        </td>
        <td>
          #{#q_unit3}
        </td>
        <td>
          #{#q_quantity3}
        </td>
        <td>
          #{#q_price3}
        </td>
      </tr>
    </tbody>
  </table>
  <!-- The summary table contains the subtotal, tax and total amount. -->
  <table class="summary">
    <tr>
      <th>
        Subtotal
      </th>
      <td>
        #{#q_subtotal}
      </td>
    </tr>
    <tr>
      <th>
        Tax
      </th>
      <td>
        #{#q_tax}
      </td>
    </tr>
    <tr class="total">
      <th>
        Total
      </th>
      <td>
        #{#q_total}
      </td>
    </tr>
  </table>
</main>
<!-- Within the aside tag we will put the terms and conditions which shall be shown below the invoice table. -->
<aside>
  <!-- Before the terms and conditions we will add another blue divider line with the help of the HR tag. -->
  <hr />
  <div>
    <div>
      <b>Terms & Conditions</b>
      <p>
        Please make payment within 30 days of issue of the invoice
      </p>
    </div>
    <div>
      <b>Payment Options</b>
      <ul>
        <li>Paypal</li>
        <li>Credit Card</li>
      </ul>
    </div>
  </div>
</aside>

Discover more from Questetra Support

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top