PDF export of documents

Please add export document as PDF feature.

2 Likes

I also think this is an important feature to be able to share information out of Fibery.

I have been using pdfmonkey.io to generate pdfs from individual entities using an action button (doesn’t work for views because there are multiple entities or documents). It seems to work fine, but there is an know bug with getDocumentContent() method which causes some linked entities in Rich Text Areas to not be resolved and so your final PDF will have missing bits of content. There is an issue with embeded images as well as those can’t be accessed directly by another site.

Happy to share the workflow if that is useful to anyone.

That sounds really interesting. If you can share the action button code that would be really good, thanks.

Apologies for the delay in responding. Here is the code for the action button:

// this action button uses the pdfmonkey.io API to generate pdf
// documents from fibery records/entities

// Fibery API and HTTP services
const fibery = context.getService('fibery');
const http = context.getService('http');
const utils = context.getService("utils");

// define the time zone offset (has to be hardcoded right now)
const timeOffset = {{UTC_TZ_OFFSET}};

for (const entity of args.currentEntities) {
    // get the meeting date (object with start and end)
    const meetingDateTime = entity['Date'];
    const meetingDateStart = new Date(meetingDateTime.start);
    meetingDateStart.setHours(meetingDateStart.getHours() + timeOffset);
    const meetingDateEnd = new Date(meetingDateTime.end);
    meetingDateEnd.setHours(meetingDateEnd .getHours() + timeOffset);

    // get the subject of meeting (name of entity)
    const meetingSubject = entity['Name'];

    // get the meeting notes (RTF) field
    const meetingNotes = entity['Notes'];
    const notesContent = await fibery.getDocumentContent(meetingNotes.secret, "html");

    // get collection fields query the API and provide the list of fields
    const attendeeList = await fibery.getEntityById(entity.type, entity.id, ['Attendees']);
    const nameArray = [];
    attendeeList['Attendees'].forEach(function (person) {
        nameArray.push(person.Name);
    });
    
    // call pdfmonkey.io api to generate the pdf document
    const objDocument = await http.postAsync('https://api.pdfmonkey.io/api/v1/documents', {
        body: {
            "document": {
                "document_template_id": "{{PDF_MONKEY_TEMPLATE_ID}}",
                "payload": "{ \"subject\": \"" + meetingSubject + "\", \"datestart\": \"" + meetingDateStart + "\" , \"dateend\": \"" + meetingDateEnd + "\", \"attendees\": " + JSON.stringify(nameArray) + ", \"notes\": " + JSON.stringify(notesContent) + " }",
                "status": "pending"
            }
        },
        headers: { 
            'Content-type': 'application/json', 
            'Authorization': 'Bearer {{PDF_MONKEY_API_KEY}}' }
    });

}

You will need to replace the following in the code:

  • {{UTC_TZ_OFFSET}} : replace with your timezone offset (-12 to +12)
  • {{PDF_MONKEY_TEMPLATE_ID}} : replace with your pdfmonkey.io template ID
  • {{PDF_MONKEY_API_KEY}}: replace with your pdfmonkey.io API key

I would like to add to the code to wait for the PDF to be generated and then grab the address and store it a field in the entity. I will update the codes once I’ve done that.

The template in PDF monkey can be as simple or complicated as you wish:

HTML Template

<table class="letterhead">
  <tr style="height: 40px">
    <td class="logobox" rowspan="3">LOGO</td>
    <td class="title" colspan="5">Meeting Notes</td>
  </tr>
  <tr style="height: 25px">
    <td style="width: 80px; font-weight: bold">Subject:</td>
    <td style="width: 500px; border-bottom: 1px solid #ddd;" colspan="4">{{subject}}</td>
  </tr>
  <tr style="height: 25px">
    <td style="width: 80px; font-weight: bold">Project:</td>
    <td style="width: 500px; border-bottom: 1px solid #ddd;">{{project}}</td>
    <td style="width: 5px; font-weight: bold"></td>
    <td style="width: 45px; font-weight: bold">Date:</td>
    <td style="width: 150px; border-bottom: 1px solid #ddd;">{{datestart | date: "%Y %b %-d" }}</td>
  </tr>
  <tr style="height: 25px">
    <td style="width: 120px"></td>
    <td style="width: 80px; font-weight: bold">Location:</td>
    <td style="width: 500px; border-bottom: 1px solid #ddd;">{{location}}</td>
    <td style="width: 5px; font-weight: bold"></td>
    <td style="width: 45px; font-weight: bold">Time:</td>
    <td style="width: 150px; border-bottom: 1px solid #ddd;">{{datestart | date: "%k:%M" }} - {{dateend | date: "%k:%M" }}</td>
  </tr>
</table>

<table class="letterhead">
  <tr style="height: 10px">
    <td style="width: 13px"></td>
    <td></td>
  </tr>
  <tr style="height: 2px">
    <td></td>
    <td style="border-bottom: 1px solid #000;"></td>
  </tr>
   <tr style="height: 2px">
     <td></td>
    <td style="border-bottom: 1px solid #000;"></td>
  </tr>
  <tr>
    <td></td>
    <td style="font-weight: bold">Attendees</td>
  </tr>
  <tr style="">
    <td></td>
    <td>
      <ul style="list-style-type: square">
        {% for attendee in attendees %}
          <li>{{attendee}}</li>
        {% endfor %}
      </ul>
    </td>
  </tr>
  <tr style="height: 2px">
    <td></td>
    <td style="border-bottom: 1px solid #000;"></td>
  </tr>
   <tr style="height: 2px">
     <td></td>
    <td style="border-bottom: 1px solid #000;"></td>
  </tr>
  <tr>
    <td></td>
    <td style="font-weight: bold">Notes</td>
  </tr>
  <tr>
    <td></td>
    <td class="notecontent">{{notes}}</td>
  </tr>
</table>

CSS

.letterhead {
	width: 100%;
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
	font-size: 11pt;
}
.title {
  font-size: 22pt;
  font-weight: bold;
}
.logobox {
  width: 120px;
}
.notecontent{
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}

Data Structure

{
  "subject": "Test Meeting Notes",
  "project": "Testing",
  "datestart": "2021-03-05T11:00:00.000Z",
  "dateend": "2021-03-05T20:00:01.000Z",
  "location": "",
  "attendees": ["Brian Griffin", "James Woods", "Peter Griffin"],
  "notes": "This is a test"
}

Just a few caveats:

  • It seems at the moment that entity references do not resolve properly and sometimes are missing from the HTML that is returned by Fibery. The team is aware of this but I don’t know when a fix is going to be provided
  • Images in rich text area are not accessible outside of Fibery without some sort of authentication. So if you have images, those won’t should up in the generated PDF

I think it would be much better if Fibery had an internal capability to do this. I will link to this thread from the Templates thread because I think the two are related.

1 Like