Guide
In this guide, we'll understand how to generate and send a PDF file on a use case.
Let's imagine you're a freelancer who offers services for website creation and maintenance. After a project completion, you would like to send an invoice to a customer.
This means you want to automate the following flow when project's status is set to 'Done':
Generate a custom-designed PDF invoice containing names and costs of services provided.
Send the generated PDF file to a customer.
Let's do it using Automation Rule.
Step 1. Set space structure
Let's configure a Space first - we need to add Databases and Formulas required for the Automation Rule.
Databases in Freelance Space
Customer Database with fields Name, Email, Address.
Project Database with fields Name, State, Description, Customer (many-to-one relation to Customer) and Files.
Task Database with fields Name, State, Description, Cost, Project (many-to-one relation to Project).
Formulas on Project Database
Total Cost is calculated from cost of all Tasks in 'Done' state using Tasks.Filter(State.Final = true).Sum(Cost)
Delivered is a collection of completed Tasks of Project calculated using Tasks.Filter(State.Final = true)
Step 2. Set trigger for automation rule
Using Fibery terminology, you would like to set Automation that perform the following actions:
Generate PDF file using Attach PDF using HTML template (first Action).
Send email with the generated PDF file to a customer (second Action).
To set this Automation, you need to choose Project Database, click Automations in the upper right corner, and choose Rule in the opened window.
Let's set a Rule trigger, or an answer to 'When' question.
Rule should be executed when state is changed to 'Done' and 'Total Cost' is greater than 0.
Let's continue to Actions, or answers to 'Then' question.
Step 3. Add action 'Attach PDF using template'
To generate a custom-designed PDF invoice containing names and costs of services provided:
Select Attach PDF using template Action.
Provide an HTML template to generate a PDF file from it. We recommend searching the web for a suitable template to use as a starting point for your specific needs. In this example, we used an HTML template that is based on Simple HTML Invoice Template (it's inserted as code block below).
Tick TREAT TEMPLATE AS HTML PAGE checkbox to keep the custom formatting.
Here is the first Automation Action:
And here is an HTML example that we used as Template:
<!DOCTYPE html>
{! Delivered:Name,Cost !}
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title></title>
<!-- Invoice styling -->
<style>
.invoice-box {
max-width: 800px;
margin: auto;
padding: 30px;
font-size: 16px;
line-height: 24px;
color: #555;
}
.invoice-box table {
width: 100%;
line-height: inherit;
text-align: left;
border-collapse: collapse;
}
.invoice-box table td {
padding: 5px;
vertical-align: top;
}
.invoice-box table tr td:nth-child(2) {
text-align: right;
}
.invoice-box table tr.top table td {
padding-bottom: 20px;
}
.invoice-box table tr.top table td.title {
font-size: 45px;
line-height: 45px;
color: #364357;
}
.note {
font-size: 20px;
color: #364357;
}
.invoice-box table tr.information table td {
padding-bottom: 100px;
}
.invoice-box table tr.heading td {
background: #eee;
border-bottom: 1px solid #ddd;
font-weight: bold;
}
.invoice-box table tr.details td {
padding-bottom: 100px;
}
.invoice-box table tr.item td {
border-bottom: 1px solid #eee;
}
.invoice-box table tr.item.last td {
border-bottom: none;
}
.invoice-box table tr.total td:nth-child(2) {
padding-top: 60px;
font-weight: bold;
font-size: larger;
}
@media only screen and (max-width: 600px) {
.invoice-box table tr.top table td {
width: 100%;
display: block;
text-align: center;
}
.invoice-box table tr.information table td {
width: 100%;
display: block;
text-align: center;
}
}
</style>
</head>
<body>
<div class="invoice-box">
<table>
<tr class="top">
<td colspan="2">
<table>
<tr>
<td class="title">
Freelance Studio
</td>
<td>
<div class="note">
Invoice #: <b>{{Public Id}}</b><br/>
Date: <b><%= (new Date()).toLocaleDateString('en-US') %></b>
</div>
</td>
</tr>
</table>
</td>
</tr>
<tr class="information">
<td colspan="2">
<table>
<tr>
<td>
Freelancer's Bank<br/>
<b>Account No</b>
</td>
<td>
777 Flower St
<br/>
Sometown, USA
</td>
</tr>
</table>
</td>
</tr>
<tr class="heading">
<td>Bill to</td>
<td></td>
</tr>
<tr class="details">
<td class="note">
<b>{{Customer.Name}}</b>
</td>
<td>
{{Customer.Address}}
</td>
</tr>
<tr class="heading">
<td>{{Name}} Services</td>
<td></td>
</tr>
<% for(let task of Entity.Delivered) {%>
<tr class="item">
<td><%= task.Name %></td>
<td><%= task.Cost %></td>
</tr>
<%}%>
<tr class="total">
<td></td>
<td>Total: ${{Total Cost}}</td>
</tr>
</table>
</div>
</body>
</html>
File name is built using formula: "Invoice #" + [Step 1 Project].[Public Id]
{! Delivered:Name,Cost !} used for hidden initialization of collection which contains completed Tasks.
Step 4. Add action 'Send email'
To send the generated PDF file to a customer, use Send Email.
[Step 1 Project].Files.Filter(StartsWith(Name, "Invoice") = true) is used for sending only invoice file.
[Step 1 Project].Customer.Email is used as a customer email.
Here is the final second Automation Action:
Example of automation rule execution
Let's assume the project status is changed to 'Done'.
The customer will receive the following email message:
And the PDF file content is the following:
If anything from this guide is unclear or you have any questions — please contact us in support chat!
FAQ
Can I have a formula inside the HTML that gets the date from today?
You can use javascript to get the current datetime, e.g.
<%= new Date() %>
Of course, you might want a nicer format, e.g.
<%= new Date().toLocaleDateString("en-US") %>
You can also can pick a locale setting to format the date according to your preferences, e.g.
<%= new Date().toLocaleDateString(“de-DE”) %>
How to Reference a Date Field in an HTML Template
When using an HTML template, some fields (including Date fields) may not appear when dumping all Entity fields. This usually happens when you try to access them inside JavaScript, not directly in the template markup.
<%
const fibery = context.getService('fibery');
// Fetch entity with specific fields
const EntityPlus = await fibery.getEntityById(
Entity.type,
Entity.Id,
['Creation Date']
);
// Access the Date field
const CreationDate = EntityPlus['Creation Date'];
%>
<%= CreationDate %>