PDF invites printer tutorial

Tutorial for creating a software robot to create personalized PDF invitations based on an Excel file, using Robot Framework and RPA Framework.

Starting from an Excel file, this robot will generate a personalised PDF invitation for each participant to an event.

Excel worksheet to work item to PDF files

To demonstrate the use of the Robocloud.Items library, we will split the operations that the robot performs into two different actitivies: the first activity will read the data from the Excel file and add it to the work item. The second activity, based on the data in the work item, will then generate the PDF invitations.

You can find the code for this tutorial at the example activities repository.

Prerequisites

Set up your development environment.

First activity: Excel to Work Item

In this activity the robot will:

  • collect the data from an Excel file
  • process the data into the correct format
  • add the data to the work item and exit

Initialize the software robot directory

robo init excel-to-work-item

Navigate to the directory:

cd excel-to-work-item

Robot task file

Paste the following Robot Framework code in the tasks/robot.robot file:

*** Settings ***
Documentation     Excel reader robot. Reads information from a given Excel file and
...               adds it to the work item.
Resource          keywords.robot

*** Tasks ***
Read invitations from Excel file and add them to the work item
    Store invitations in work item

Robot keywords file

Paste the following Robot Framework code in the resources/keywords.robot file:

*** Settings ***
Library           OperatingSystem
Library           RPA.Excel.Files
Library           RPA.Robocloud.Items
Variables         variables.py

*** Keywords ***
Store invitations in work item
    Set Up And Validate
    ${invitations}=    Collect invitations from the Excel file
    Load Work Item From Environment
    Set Work Item Variables    invitations=${invitations}
    Save Work Item

Set Up And Validate
    File Should Exist    ${EXCEL_FILE_PATH}

Collect invitations from the Excel file
    Open Workbook    ${EXCEL_FILE_PATH}
    ${invitations}=    Read Worksheet    header=True
    Close Workbook
    [Return]    ${invitations}

Robot keywords file explained

Let's look in detail at what we are telling our robot to do:

*** Settings ***
Library     OperatingSystem
Library     RPA.Excel.Files
Library     RPA.Robocloud.Items
Variables   variables.py

In the Settings section we declare the libraries we are going to use, and we add a reference to our variables file.

Our robot will use these libraries:

  • OperatingSystem: to manipulate files and directories
  • RPA.Excel.Files: to read the content of our Excel file
  • RPA.Robocloud.Items: to manipulate the work item

Let's have a closer look at the Keywords section:

*** Keywords ***
Store invitations in work item
    Set Up And Validate
    ${invitations}=    Collect invitations from the Excel file
    Load Work Item From Environment
    Set Work Item Variables    invitations=${invitations}
    Save Work Item

Here we are creating our own keyword that contains all the operations that the robot is going to perform. This in turn is the only keyword we are executing in our main tasks/robot.robot file.

  1. Set Up And Validate is a keyword that will check that the Excel exists and it is in the correct place, using the File Should Exist keyword, which is provided by the OperatingSystem library:

    Set Up And Validate
       File Should Exist    ${EXCEL_FILE_PATH}
  2. ${invitations}= Collect invitations from the Excel file

    Here we are creating a variable, and we are assigning to it the Excel data by using a new keyword Collect invitations from the Excel file:

    Collect invitations from the Excel file
       Open Workbook    ${EXCEL_FILE_PATH}
       ${invitations}=    Read Worksheet    header=True
       Close Workbook
       [Return]    ${invitations}

    We are using the RPA.Excel.Files library to manipulate the Excel file (Keywords: Open Workbook, Read Worksheet, Close Workbook).

  3. Load Work Item From The Environment

    This keyword is provided by the RPA.Robocloud.Items library, and it will load the work item for us, based on the environment variables. In our local setup, this will read the work item from a local JSON file. (See the Setting up the Robocloud.Items library section below.)

  4. Set Work Item Variables invitations=${invitations}

    Here we are storing our invitation data in a new variable inside the work item, using the Set Work Item Variables keyword, provided by the RPA.Robocloud.Items library.

  5. Save Work Item

    Calling this keyword we are persisting the content of the work item.

Variables file

Paste the following Python code in the variables/variables.py file:

from robot.libraries.OperatingSystem import OperatingSystem

os = OperatingSystem()
EXCEL_FILE_PATH = os.normalize_path(__file__ + "/../../devdata/Data.xlsx")

Excel file

The order information is stored in an Excel file (Data.xlsx). The file is formatted as follows:

first_namelast_nameaddresscitydatetime
ReynardMouse4 Service CenterToronto2019/07/0310:00 PM
ElisabethKilfoyle197 Ronald Regan DriveNew York2019/05/0310:20 PM
CyrilBlundon3554 Chive CircleSan Francisco2019/05/101:33 PM
VincenzPaolazzi20533 6th CrossingMilan2019/12/146:58 AM
JeannieCharge9 Michigan StreetKansas City2020/02/124:27 AM
AlexioHellis8 Grim TrailLahore2019/05/055:04 PM
LucaViel91764 Reindahl ParkNew Dehli2019/12/178:37 AM
SlyLammerts8077 Pennsylvania DriveHelsinki2020/02/0911:23 PM
LeahMithun3619 Oxford PlaceStockholm2019/10/301:15 PM
MaridelSneezum4 Cambridge CenterLondon2020/03/2611:24 AM
Download the Excel file and save it in the devdata directory.

Setting up the Robocloud.Items library

When executing our robot in a cloud environment like Robocloud, the RPA.Robocloud.Items library will store the work item in the cloud environment, sharing its contents between activities defined in the same process, without any configuration needed.

When developing our activity and running it locally, however, we want the library to store the data in a JSON file, and provide the required parameters to simulate the cloud environment. You can learn more about the internals of the RPA.Robocloud.Items library here.

Create a new file called items.json on your file system, for example at /tmp/items.json.

Paste this content into your items.json file, creating an empty but valid json file:

{}

Paste the following in devdata/env.json:

{
  "RPA_WORKITEMS_ADAPTER": "RPA.Robocloud.Items.FileAdapter",
  "RPA_WORKITEMS_PATH": "/tmp/items.json",
  "RC_WORKSPACE_ID": 1,
  "RC_WORKITEM_ID": 1
}

Edit the RPA_WORKITEMS_PATH variable to point to the items.json file on your filesystem. On macOS / Linux, use normal file paths, for example, /tmp/items.json. On Windows 10, you need to escape the path, for example, C:\\Users\\User\\items.json.

Wrap the robot

robo wrap

Run the robot

Note that we are using the -v command option, pointing to the file containing our environment variables defined above.

Windows:

robo run entrypoint.cmd -v devdata\env.json

macOS / Linux:

robo run entrypoint.sh -v devdata/env.json

Results of the first activity

After you run the robot, you will find that the items.json file in the directory you have specified in the env.json file will now contain a JSON representation of the data of the Excel file. Great! The first activity is complete!

{
  "1": {
    "1": {
      "variables": {
        "invitations": [
          {
            "first_name": "Reynard",
            "last_name": "Mouse",
            "address": "4 Service Center",
            "city": "Toronto",
            "date": "2019/07/03",
            "time": "10:00 PM"
          },
          {
            "first_name": "Elisabeth",
            "last_name": "Kilfoyle",
            "address": "197 Ronald Regan Drive",
            "city": "New York",
            "date": "2019/05/03",
            "time": "10:20 PM"
          }
          // ...
        ]
      }
    }
  }
}

Second activity: work item to PDF

In this activity the robot will:

  • retrieve the data from the work item
  • loop through the data and generate a personalized PDF for each event participant using a template into a temporary folder
  • collect all generated files into a zip archive in the output folder
  • write log and report files
  • clean up after itself by deleting the temporary folder

Initialize the software robot directory

Now that our first activity is complete, go back to your projects directory and initialise a new activity directory by issuing:

robo init work-item-to-pdf

Navigate to the directory:

cd work-item-to-pdf

Install the Robot Framework archive library

pip install --upgrade robotframework-archivelibrary && robo libs --add --pip robotframework-archivelibrary

Robot task file

Paste the following Robot Framework code in the tasks/robot.robot file:

*** Settings ***
Documentation     Invite printer robot. Creates PDF invitations to events based on data it receives
...               from the work item.
Resource          keywords.robot

*** Tasks ***
Create PDF invitations
    Process invitations

Robot keywords file

Paste the following Robot Framework code in the resources/keywords.robot file:

*** Settings ***
Library           ArchiveLibrary
Library           OperatingSystem
Library           RPA.PDF
Library           RPA.Robocloud.Items
Variables         variables.py

*** Keywords ***
Process invitations
    Set up and validate
    ${invitations}=    Collect invitations from work item
    FOR    ${invitation}    IN    @{invitations}
        Run Keyword And Continue On Failure    Create PDF file for invitation    ${invitation}
    END
    Create ZIP package from PDF files
    [Teardown]    Cleanup temporary PDF directory

Set up and validate
    File Should Exist    ${PDF_TEMPLATE_PATH}
    Create Directory    ${PDF_TEMP_OUTPUT_DIRECTORY}

Collect invitations from work item
    Load Work Item From Environment
    ${invitations}=    Get Work Item Variable    invitations
    [Return]    ${invitations}

Create PDF file for invitation
    [Arguments]    ${invitation}
    Template Html To Pdf    ${PDF_TEMPLATE_PATH}    ${PDF_TEMP_OUTPUT_DIRECTORY}/${invitation["first_name"]}_${invitation["last_name"]}.pdf    ${invitation}

Create ZIP package from PDF files
    ${zip_file_name}=    Set Variable    ${OUTPUT_DIRECTORY}/PDFs.zip
    Create Zip From Files In Directory    ${PDF_TEMP_OUTPUT_DIRECTORY}    ${zip_file_name}

Cleanup temporary PDF directory
    Remove Directory    ${PDF_TEMP_OUTPUT_DIRECTORY}    True

Robot keywords file explained

Let's look in detail at what we are telling our robot to do:

*** Settings ***
Library           ArchiveLibrary
Library           OperatingSystem
Library           RPA.PDF
Library           RPA.Robocloud.Items
Variables         variables.py

In the Settings section we declare the libraries we are going to use, and a reference to our variables file.

Our robot will use these libraries:

  • ArchiveLibrary: to create the zipped file that will contain the generated PDF files
  • OperatingSystem: to work with files and directories
  • RPA.PDF: to create our PDF files
  • RPA.Robocloud.Items: to manipulate the work item

Let's have a closer look at the Keywords section.

*** Keywords ***
Process invitations
    Set up and validate
    ${invitations}=    Collect invitations from work item
    FOR    ${invitation}    IN    @{invitations}
        Run Keyword And Continue On Failure    Create PDF file for invitation    ${invitation}
    END
    Create ZIP package from PDF files
    [Teardown]    Cleanup temporary PDF directory

Here we are creating our own keyword that contains all the operations that the robot is going to perform. This in turn is the only keyword we are executing in our main tasks/robot.robot file.

  1. Set up and validate is a keyword that will check that the template file is in place, using the File Should Exist keyword, which is provided by the OperatingSystem library, and will create a directory where we will temporarily store the PDF files.

    Set up and validate
       File Should Exist    ${PDF_TEMPLATE_PATH}
       Create Directory    ${PDF_TEMP_OUTPUT_DIRECTORY}
  2. ${invitations}= Collect invitations from work item

    Here we are creating a variable, and we are assigning to it the data from the work item by using a new keyword Collect invitations from work item:

    Collect invitations from work item
       Load Work Item From Environment
       ${invitations}=    Get Work Item Variable    invitations
       [Return]    ${invitations}

    The Load Work Item From Environment keyword is provided by the RPA.Robocloud.Items library, and it will load the work item for us, based on the environment variables. In our local setup, this will read the work item from a local JSON file. (See the Setting up the Robocloud.Items library section below.)

    After we have loaded the work item, we can get the invitations variable from it and return it.

  3. Looping over the invitations

       FOR     ${invitation}   IN  @{invitations}
           Run Keyword And Continue On Failure     Create PDF file for invitation  ${invitation}
       END
  4. Create PDF file for invitation ${invitation}

    Create PDF file for invitation
       [Arguments]    ${invitation}
       Template Html To Pdf    ${PDF_TEMPLATE_PATH}    ${PDF_TEMP_OUTPUT_DIRECTORY}/${invitation["first_name"]}_${invitation["last_name"]}.pdf    ${invitation}

    Here we are using the Template Html To Pdf keyword, provided by the RPA.PDF library to generate a PDF file based on an HTML template. The template contains placeholders that are replaced by our variables. The second argument we pass to the keyword allows us to specify the path and the name of the created PDF file. In our case, we are using the first and last name.

    The RPA.PDF library offers a variety of ways to create and interact with PDF files. Here we are using the template method.

  5. Create ZIP package from PDF files

    In this keyword we are using the ArchiveLibrary library to archive all generated PDF files into a file in the output directory:

    Create ZIP package from PDF files
       ${zip_file_name}=    Set Variable    ${OUTPUT_DIRECTORY}/PDFs.zip
       Create Zip From Files In Directory    ${PDF_TEMP_OUTPUT_DIRECTORY}    ${zip_file_name}
  6. [Teardown] Cleanup temporary PDF directory

    As the last step, we delete the directory we used to store the created PDFs temporarily:

    Cleanup temporary PDF directory
       Remove Directory    ${PDF_TEMP_OUTPUT_DIRECTORY}    True

    We are using the Remove Directory keyword from the OperatingSystem library.

    Note the True parameter, necessary to delete a non-empty directory.

Variables file

Paste the following Python code in the variables/variables.py file:

from robot.libraries.OperatingSystem import OperatingSystem

os = OperatingSystem()

EXCEL_FILE_PATH = os.normalize_path(__file__ + "/../../devdata/Data.xlsx")
PDF_TEMPLATE_PATH = os.normalize_path(
    __file__ + "/../../devdata/invite.template")
PDF_TEMP_OUTPUT_DIRECTORY = os.normalize_path(
    __file__ + "/../../output/pdf")
OUTPUT_DIRECTORY = os.normalize_path(
    __file__ + "/../../output")

PDF template file

Create a new file called invite.template in the devdata folder, and paste this content into it:

<h1>Event Invitation</h1>
<p>Dear <b>{{first_name}} {{last_name}}</b>,</p>

<p>
  You are invited to our event on <b>{{date}}</b> at <b>{{time}}</b>, at
  <b>{{address}}</b>, <b>{{city}}</b>.
</p>

<p>Bring a friend, and don't be late!</p>

<p>Kind regards,</p>

<p>Robot Events Inc.</p>

Setting up the Robocloud.Items library

Just like we did in the first activity, we need to configure the Robocloud.Items library to work locally.

Paste the following in devdata/env.json:

{
  "RPA_WORKITEMS_ADAPTER": "RPA.Robocloud.Items.FileAdapter",
  "RPA_WORKITEMS_PATH": "/tmp/items.json",
  "RC_WORKSPACE_ID": 1,
  "RC_WORKITEM_ID": 1
}

Edit the RPA_WORKITEMS_PATH variable to point to the items.json file on your filesystem. On macOS / Linux, use normal file paths, for example, /tmp/items.json. On Windows 10, you need to escape the path, for example, C:\\Users\\User\\items.json.

By pointing to the same file that we used in the first activity and by specifying the same workspace and work item id, we are now effectively sharing data between the two activities. This way, we are simulating what happens in Robocloud when two activities are added to the same process.

Wrap the robot

robo wrap

Run the robot

Note that we are using the -v command option, pointing to the file containing our environment variables defined above.

Windows:

robo run entrypoint.cmd -v devdata\env.json

macOS / Linux:

robo run entrypoint.sh -v devdata/env.json

Results of the second activity

After you run the robot, you will find a zip archive PDFs.zip file in the temp/robocode/work-item-to-pdf/output directory. Extract it and you will see the PDF invitations according to the data in the Excel file.

Advantages of using the Robocloud.Items library

By using the Robocloud.Items library, a complex workflow can be broken in multiple activities that share the same data, held by the work item. Each activity gets the work item from the previous activity, can add and remove data from it, and it passes it on to the next one in the same process.

Organizing a process into multiple activities can have multiple advantages:

  • better separation of concerns
  • the same smaller activities can be reused in different contexts
  • when run in Robocloud, each activity can be run in a different environment by a different worker, for example combining part of the process running in the cloud and part of it in physical desktop machines in an intranet.

Summary

You created a robot to automate the task of filling in invitations, congratulations!

During the process, you learned some concepts and features of the Robot Framework and the RPA Framework:

  • Splitting a process into two activities, passing data between via the RPA.Robocloud.Items library
  • Using the work item library locally (items.json)
  • Validating task prerequisites (File Should Exist)
  • Reading Excel files and transforming to business entities (RPA.Excel)
  • Creating ZIP archives with the ArchiveLibrary library
  • Installing additional libraries and updating the conda.yaml file (pip install --upgrade robotframework-archivelibrary && robo libs --add --pip robotframework-archivelibrary)
  • Creating an executable package (robo wrap)
  • Running robot files, providing environment variables as a file (robo run entrypoint.sh -v devdata/env.json, robo run entrypoint.cmd -v devdata\env.json)
  • Organizing your project files in subdirectories (robo init excel-to-work-item)