Create Invoice (Display on Thunkable live,Send by email with pdf attachment)

Hello after many research I finally succeeded in creating dynamic invoices in pdf and manage the sending.

Thanks @cttricks for his tutorial which helped me a lot.

We will use
https://www.google.com/script/start/

https://x.thunkable.com/

Project : REMIX

1.Launch https://www.google.com/script/start/ and create a new project

Image from Gyazo

2. Paste this code on your code.gs

function doPost(e) {


    var productList = [];
    var json = (JSON.parse(e.parameters.facture));
    var products = json.table.product.products;

   var item;

for (var item_index in products) {
  item = products[item_index];
  productList.push(
'<tbody>\n' + 
'<tr style="height: 68px;">\n' +
'<td style="color: #636363; border: 1px solid #e5e5e5; padding: 12px; text-align: left; vertical-align: middle; font-family: '+"'Helvetica Neue'"+', Helvetica, Roboto, Arial, sans-serif;overflow-wrap: break-word; height: 68px; width: 25.4%;">'+ item.produit + '</td>\n'+ 
'<td style="color: #636363; border: 1px solid #e5e5e5; padding: 12px; text-align: left; vertical-align: middle; font-family: '+"'Helvetica Neue'"+', Helvetica, Roboto, Arial, sans-serif; height: 68px; width: 28.4%;">'+ item.quantite + '</td>\n'+ 
'<td style="color: #636363; border: 1px solid #e5e5e5; padding: 12px; text-align: left; vertical-align: middle; font-family: '+"'Helvetica Neue'"+', Helvetica, Roboto, Arial, sans-serif; height: 68px; width: 46%;">'+ item.prix + '</td>\n' +
'</tr>\n'+
'</tbody>\n');

}
if(json.mail.pdf.pdfSend == true) 
   {
  var imgb64 ="";
  imgb64 = HtmlService.createTemplateFromFile('imgb64');
  imgb64 = imgb64.evaluate().getContent();
   }
  var html =     HtmlService.createTemplateFromFile('EmailTemplate');
  html.json = json;
  html.productList = productList.join('');
  var template = html.evaluate().getContent();


 if(json.mail.send.sendEmail == true) 
   {
  if(json.mail.pdf.pdfSend == true) 
   {
    var template2 = template;
    template2= template2.replace(json.style.factureHeaderImg,imgb64);
    var blob = Utilities.newBlob(template2, "text/html", "text.html");
    blob.setName(json.mail.pdf.pdfName + ".pdf");
    var pdf = blob.getAs("application/pdf");


        MailApp.sendEmail({
   to: json.mail.send.to,
   subject: json.mail.send.subject,
   htmlBody:  template, 
   attachments: [pdf]
 
   });
   }
   else{
             MailApp.sendEmail({
   to: json.mail.send.to,
   subject: json.mail.send.subject,
   htmlBody:  template
 
   });
   }
   }
    return ContentService.createTextOutput(template)
 
}

3. Creates 2 html files

Image from Gyazo

4.

a) Change the name of the first html file to “EmailTemplate” and copy this code

<!DOCTYPE html>
<html>
  <meta charset="utf-8">
  <head>
    <base target="_top">
  </head>
  <body>
    <div class="">
<div style="padding: 0;">
<div id="m_8514590629868396670wrapper" dir="ltr" style="background-color: #<?= json.style.factureBackgroundColor;?>; margin: 0; padding: 70px 0; width: 100%;">
<table border="0" width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td align="center" valign="top">
<div id="m_8514590629868396670template_header_image">
<p style="margin-top: 0;"><img class="CToWUd" style="border: none; display: inline-block; font-size: 14px; font-weight: bold; height: auto; outline: none; text-decoration: none; text-transform: capitalize; vertical-align: middle; height: 128px; width: 128px; max-width: <?= json.style.factureSizeImage;?>; margin-left: 0; margin-right: 0;" src="<?= json.style.factureHeaderImg ?>"/></p>
</div>

<table id="m_8514590629868396670template_container" style="background-color: #ffffff; border: 1px solid #dedede; border-radius: 3px;" border="0" width="600" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td align="center" valign="top">
<table id="m_8514590629868396670template_header" style="background-color: <?= json.style.factureHeaderColor;?>; color: #00000; border-bottom: 0; font-weight: bold; line-height: 100%; vertical-align: middle; font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; border-radius: 3px 3px 0 0;" border="0" width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td id="m_8514590629868396670header_wrapper" style="padding: 36px 48px; display: block;">
<h1 style="font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; font-size: 30px; font-weight: 300; line-height: 150%; margin: 0; text-align: left; color: #00000; background-color: inherit;"> <?= json.labels.factureHeaderTitle;?><?= json.labels.factureHeaderDescription;?></h1>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td align="center" valign="top">
<table id="m_8514590629868396670template_body" border="0" width="600" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td id="m_8514590629868396670body_content" style="background-color: <?= json.style.factureBodyColor;?>;" valign="top">
<table border="0" width="100%" cellspacing="0" cellpadding="20">
<tbody>
<tr>
<td style="padding: 0px 48px 32px;" valign="top">
<div id="m_8514590629868396670body_content_inner" style="color: #636363; font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; font-size: 14px; line-height: 150%; text-align: left;">
<p style="margin: 0 0 16px;"><?= json.labels.factureBodyTop;?></p>
<h2 style="color: #000; display: block; font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; font-size: 18px; font-weight: bold; line-height: 130%; margin: 0 0 18px; text-align: left;"><a style="font-weight: normal; text-decoration: underline; color: #202020;" target="_blank" rel="noopener" data-saferedirecturl=""><?= json.labels.BodyBillNumber;?></a><?= json.labels.factureDate; ?></h2>
<div style="margin-bottom: 40px;">
<table style="color: #636363; border: 1px solid #e5e5e5; vertical-align: middle; width: 100%; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; height: 321px;" border="1" cellspacing="0" cellpadding="6">
<thead>
<tr style="height: 46px;">
<th style="color: #636363; border: 1px solid #e5e5e5; vertical-align: middle; padding: 12px; text-align: left; height: 46px; width: 25.4%;" scope="col"><?= json.table.product.factureColumnProduct1;?></th>
<th style="color: #636363; border: 1px solid #e5e5e5; vertical-align: middle; padding: 12px; text-align: left; height: 46px; width: 28.4%;" scope="col"><?= json.table.product.factureColumnProduct2;?></th>
<th style="color: #636363; border: 1px solid #e5e5e5; vertical-align: middle; padding: 12px; text-align: left; height: 46px; width: 46%;" scope="col"><?= json.table.product.factureColumnProduct3;?></th>
</tr>
</thead>

<?!= productList ?>

<tfoot>
<tr style="height: 67px;">
<th style="color: #636363; border-width: 4px 1px 1px; border-style: solid; border-color: #e5e5e5; border-image: initial; vertical-align: middle; padding: 12px; text-align: left; height: 47px; width: 53.8%;" colspan="2" scope="row"><?= json.table.payment.factureRowPayment1;?></th>
<td style="color: #636363; border-width: 4px 1px 1px; border-style: solid; border-color: #e5e5e5; border-image: initial; vertical-align: middle; padding: 12px; text-align: left; height: 47px; width: 46%;"><?= json.table.payment.factureRowPaymentContent1;?></td>
</tr>
<tr style="height: 46px;">
<th style="color: #636363; border: 1px solid #e5e5e5; vertical-align: middle; padding: 12px; text-align: left; height: 46px; width: 53.8%;" colspan="2" scope="row"><?= json.table.payment.factureRowPayment2;?></th>
<td style="color: #636363; border: 1px solid #e5e5e5; vertical-align: middle; padding: 12px; text-align: left; height: 46px; width: 46%;"><?= json.table.payment.factureRowPaymentContent2;?></td>
</tr>
</tfoot>
</table>
</div>
<table id="m_8514590629868396670addresses" style="width: 100%; vertical-align: top; margin-bottom: 40px; padding: 0;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="text-align: left; font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; border: 0; padding: 0;" valign="top" width="50%">
<h2 style="color: #636363; display: block; font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; font-size: 18px; font-weight: bold; line-height: 130%; margin: 0 0 18px; text-align: left;"><?= json.table.address.factureColumnAddress1;?></h2>
<address style="padding: 12px; color: #636363; border: 1px solid #e5e5e5;"><?= json.table.address.factureColumnAddressContent1;?></address></td>
<td style="text-align: left; font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; padding: 0;" valign="top" width="50%">
<h2 style="color: #636363; display: block; font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; font-size: 18px; font-weight: bold; line-height: 130%; margin: 0 0 18px; text-align: left;"><?= json.table.address.factureColumnAddress2;?></h2>
<address style="padding: 12px; color: #636363; border: 1px solid #e5e5e5;"><?= json.table.address.factureColumnAddressContent2;?></address></td>
</tr>
</tbody>
</table>
<p style="margin: 0 0 16px;"><?= json.labels.factureGreetings;?></p>
</div>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td align="center" valign="top">
<table id="m_8514590629868396670template_footer" border="0" width="600" cellspacing="0" cellpadding="10">
<tbody>
<tr>
<td style="padding: 0; border-radius: 6px;" valign="top">
<table border="0" width="100%" cellspacing="0" cellpadding="10">
<tbody>
<tr>
<td id="m_8514590629868396670credit" style="border-radius: 6px; border: 0; color: #8a8a8a; font-family: 'Helvetica Neue',Helvetica,Roboto,Arial,sans-serif; font-size: 12px; line-height: 150%; text-align: center; padding: 24px 0;" colspan="2" valign="middle">
<p style="margin: 0 0 16px;"><?= json.labels.factureBottomMessage; ?></p>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>

</div>

</div>

</div>
  </body>
</html>

b) Change the name of the second html file to “imgb64” and copy this code

data:image/png;base64, (YOUR BASE64 IMAGE)

Convert your image to base64 there are many converters on google

5. Deploy your script, Deploy > Webapp > access > everyone

6.Allow access until you get a URL like this, In the project define the url of the api component with this url copy
Image from Gyazo

https://script.google.com/macros/s/AKfycby2cv8GDE0My0dfgdfgXBHHguJwxQJ5UK0r6_ty3xfUqRMdfgdfgwegdfgaNQJ5PjfZyg/exec

7.Create a file index.html on your desktop and copy this code
Drag it into thunkable and set the web viewer url to index.html

<html><head>
<script src="https://thunkable.github.io/webviewer-extension/thunkableWebviewerExtension.js" type="text/javascript"></script>
<script type="text/javascript">
// when we get a message from the app, display it on the page
ThunkableWebviewerExtension.receiveMessage(function(message) {
 document.body.innerHTML = message;
});
</script>
<title>Facture</title>
</head>
<body>
</body>
</html>

Image from Gyazo

8. Modify the data with your variables and you’re done
Image from Gyazo

9. Test :slight_smile:
Image from Gyazo
Image from Gyazo

Browser Gmail view (html)
Image from Gyazo

Browser pdf view
Image from Gyazo
I hope I’ve made myself clear, don’t hesitate to tell me if I’ve made mistakes or if you need information

8 Likes

This is really awesome work I can’t wait to test it out

5 Likes

I hope it will be useful to you, with pleasure

1 Like