Sales quotation

Walk-through to creating a sample sales quote using Documotor

Introduction

Consider a furniture company creating a sales quote for one of its clients. Here's the sample sales quote that we'll generate from a Documotor recipe. The furniture needs to be grouped by type, and the subtotals and taxes need to be calculated at each step. Data describing the products or services is available, but the company needs a template and a way to automate the process of populating the template.

What will I learn?

After following this guide, you'll be able to create a moderately complex template from start to finish in Documotor. More specifically, you'll be able to:

  • Perform and output calculations on input data.
  • Format dates and numbers for displaying in the final document.
  • Insert text fields, images and links into a Documotor template.
  • Use nested repeaters to display dynamic tables.

Prerequisites

You'll need access to a Documotor tenant and a solid understanding of the platform. It's assumed you've completed the other template guides. Also, you should be comfortable with JMESPath to the degree outlined in the data transformation guides.

Sample data

Here's the sample data:

{
  "clientInfo": {
    "contactPersons": [
      "Jane Doe",
      "John Doe"
    ],
    "businessName": "Acme Corporation",
    "addressLine1": "Main Street 1",
    "addressLine2": "Anytown 10000, Ruritania"
  },
  "companyInfo": {
    "contactPerson": "Jill Doe",
    "businessName": "Contoso",
    "addressLine1": "High Street 1",
    "addressLine2": "Anycity 1000, Atlantis"
  },
  "products": [
    {
      "category": "sofas",
      "SKU": 1,
      "name": "Blue",
      "noOfUnits": "3",
      "unitRate": 2999,
      "image": "https://stsharedocumotor001.blob.core.windows.net/public-documentation/SalesQuote/BlueSofa.jpeg"
    },
    {
      "category": "sofas",
      "SKU": 2,
      "name": "Yellow",
      "noOfUnits": "2",
      "unitRate": 3499,
      "image": "https://stsharedocumotor001.blob.core.windows.net/public-documentation/SalesQuote/YellowSofa.jpeg"
    },
    {
      "category": "chairs",
      "SKU": 3,
      "name": "Comfy",
      "noOfUnits": "6",
      "unitRate": 599,
      "image": "https://stsharedocumotor001.blob.core.windows.net/public-documentation/SalesQuote/ComfyChair.jpeg"
    }
  ],
  "companyWebsite": "http://www.example.com/",
  "logo": "https://stsharedocumotor001.blob.core.windows.net/public-documentation/SalesQuote/logoipsum-216.png"
}

Copy it, navigate to the Data view, and inside Sample Data, select the pen button to enter edit mode, then paste the data and update it by using the arrow button next to the pen.

Let's examine the data. The file contains info about the client, the buyer, and the seller. Each element of the products array is an object representing a product. Finally, a link for the company website and a link to a logo are provided.

Template

Assume that some sort of template is available, and that the template works as a starting point for a process that includes a lot of manual copy-paste work. Download this template, and then navigate to the Template view and upload it using the upload button in the right side of the Binding Editor toolbar.

Notice that this template already follows best practice guidelines for Documotor, where the data that's going to be dynamically inserted is indicated by placeholders enclosed in square brackets []. As such, the template makes a great starting point for a Documotor template.

Set up dynamics

This guide will walk you through using the following bindings:

  • Image
  • Repeat (including nested Repeat bindings)
  • TextElement
  • Hyperlink
  • Locked

Additionally, we'll assume you're familiar with Field bindings from previous guides. The complexity of the template will require an inspection of which pieces of data are needed in order to generate the document. After we get an understanding of which data is needed, we'll be able to transform the data so it fits the require format, and do any calculations that are necessary.

Image

We'll start by inserting an image in the header of the file. Before you upload a template in Documotor, open Microsoft Word and insert an Image content control into the header, around the placeholder for an image. Select the image placeholder in the header, go to the Developer tab, in the Controls section, and select Picture Content Control. Repeat the same procedure for the image placeholder in the first column of the table. You're ready to create a recipe in Documotor at a location of your choosing, like the previous templates. Then upload the template to the recipe.

The insertion of the image binding will be straightforward after obtaining the data.

Repeat

The repeat binding enables insertion of data from arrays. It acts by going through all of the array elements and repeating the content inside of the content control once for each element of the array.

Basic repeat

Notice the [Contact Persons] placeholder. There is indeed an array of contact persons at clientInfo.contactPersons, and the way to insert them into a template is to use a combination of a Repeat and a Field binding.

Repeating tables

Look at the structure of the tables in the sample document. Notice that there's one table for each product category, and inside each table, there's one row for each document. This means that we need an array-of-arrays structure in our data; the encompassing array will be the basis for the repeat binding on the tables, and the array elements will be the basis for repeating rows of each table.

Thus, you'll have to reformat data slightly to yield a grouping of products by category. Some data is also missing, but can be calculated from the data that is present. All of this needs to be done in the transformation.

Numbers

Looking at the template and the input data, one can see that we'll have to calculate the prices per product, i.e., we'll have to multiply the unit rate with the amount of units purchased. Then, we'll have to sum all the prices of different products of the same type, and calculate the tax amount and the subtotal, including tax. Finally, these amounts need to be summed across different product types as well to provide the final total with and without tax. All of these calculations will be performed in the transformation.

Locked

It's desirable that the recipient doesn't have the option of modifying the table of prices. Therefore, we'll use the Locked binding to prevent the table from being editable.

We now have a good idea of what sort of data is necessary to produce a document like the one in the example. Therefore, we'll now define a transformation to transform the input data into a structure that is more suitable for the document that we want to create.

TextElement

To insert a text element in a manner similar to the one that is normally used, you should first upload a terms and conditions document to your unit. Here is the document that should be inserted. Upload it anywhere as a Word recipe and fetch the recipe ID from the URL - it is the last portion of the URL, following /docx/. Then create a data source that looks like this:

Example data source holding a template ID.

Example data source holding a template ID.

We'll return to the text element when we insert it from the transformation.

Transformation

Here is where we'll structure and generate all the data that is needed for the template.

Insert correct data

Some of the data that we receive is perfectly ready to be inserted into a document. Specifically, notice that we didn't need to edit any of the clientInfo, companyInfo, logo and website properties. Therefore, we'll simply add the same properties to our transformed data:

{
  clientInfo: @.clientInfo,
	
	companyInfo: @.companyInfo,

	companyWebsite: @.companyWebsite,

	logo: @.logo
}

Add current date

With JMESPath, we can always add the date of document generation to the document. Here's how to add the current time property using current_time and format it arbitrarily using format:

  // Fetch the current time and format it.
	currentDate: format(current_time(`0`), 'MMMM dd, yyyy', 'en-US'),

Group and calculate

As noted earlier, we'll have to group the products by category to obtain the table structure present in the goal document. To do that, we'll use the group_adjacent function with the products array and the category property as parameters, combining this with sort_by. This will group the products that have the same value of the category property. However, we'll also need to update some product data and category data on the way. Here is a representation of the desired structure in the data:

  • Entirety of payload
    • Date
    • Tax rate
    • Product categories
      • Products
        • Subtotals per product
      • Subtotals per product type
      • Tax per product type
      • Totals per product type
    • Subtotals
    • Tax
    • Total

Notably, we see that each of our products needs to have a total property added indicating the price for the given number of properties rather than the unit rate. Similarly, each of our categories needs to have its own subtotal, tax and total. To do that, we'll use the combination of map and replace_properties functions. map applies an arbitrary transformation to each of the elements of an array, and replace_properties will add the needed properties to each of the objects.

Here is the transformation:

{
  categories: map({

		// Capitalize the name of the category.
		category: to_titlecase(@[0].category, 'en-US'), 

		// Add product-level properties.
		products: map(replace_properties(@, 
		{
			// Add the product-level total.
			total: multiply(@.noOfUnits, @.unitRate),
		}, `true`), @),

		// Category-level subtotal.
		subtotal: sum($.products[*].total),

		// Tax amount is tax rate times the subtotal.
		taxAmount: multiply(parent($).VATRate, $.subtotal),

		// Total is subtotal plus tax amount.
		total: add($.subtotal, $.taxAmount),
		
	}, group_adjacent(sort_by(products, &category), &category)),
}

Notice that we're call the outermost map function on the grouping of the products.

Next, let's add the last global properties to the data payload.

{
  // The global subtotal is the sum of subtotals of all product types.
	subtotal: sum($.categories[*].subtotal),

	// The global tax amount is the subtotal multiplied by the VAT rate.
	taxAmount: multiply($.subtotal, $.VATRate),

	// The global total is the sum of the subtotal and the tax amount.
	total: add($.subtotal, $.taxAmount)
}

Finally, we need to insert a terms and conditions document. Make sure you created the data source as instructed earlier. Then, we use the template and datasource bindings as follows:

	terms: template(datasource('TermsAndConditions', 'level', 'termsAndConditions').id, get_stage_id(), `{}`)

The inner, datasource binding fetches the row of the TermsAndConditions data source whose value of level column is equal to 'termsAndConditions' as an object whose id property is retrieved immediately. Then the template binding fetches the template with that id. The function get_stage_id specifies the current stage, but it's unlikely to retrieve anything, unless you already staged some of your templates.

Finally, since the numbers used in the document represent currency, and they will be displayed in a document, we will format all of them into a currency format in DKK. Bringing all of these transformations together, we have:

{
	clientInfo: @.clientInfo,
	
	companyInfo: @.companyInfo,

	companyWebsite: @.companyWebsite,

	logo: @.logo,
	
	// Fetch the current time and format it.
	currentDate: format(current_time(`0`), 'MMMM dd, yyyy', 'en-US'),

	// Define the VAT rate of your locale.
	VATRate: `0.25`,

	categories: map({

		// Capitalize the name of the category.
		category: to_titlecase(@[0].category, 'en-US'), 

		// Add product-level properties.
		products: map(replace_properties(@, 
		{
			// Add the product-level total.
			total: multiply(@.noOfUnits, @.unitRate),

			// Format the total.
			totalFormatted: format($.total, 'c', 'da-DK'),

			// Format the unit rate, since that is also displayed in the table.
			unitRateFormatted: format(@.unitRate, 'c', 'da-DK')

		}, `true`), @),

		// Category-level subtotal.
		subtotal: sum($.products[*].total),
		subtotalFormatted: format($.subtotal, 'c', 'da-DK'),

		// Tax amount is tax rate times the subtotal.
		taxAmount: multiply(parent($).VATRate, $.subtotal),
		taxAmountFormatted: format($.taxAmount, 'c', 'da-DK'),

		// Total is subtotal plus tax amount.
		total: add($.subtotal, $.taxAmount),
		totalFormatted: format($.total, 'c', 'da-DK')
		
		}, group_adjacent(sort_by(products, &category), &category)),
	
	// The global subtotal is the sum of subtotals of all product types.
	subtotal: sum($.categories[*].subtotal),
	subtotalFormatted: format($.subtotal, 'c', 'da-DK'),

	// The global tax amount is the subtotal multiplied by the VAT rate.
	taxAmount: multiply($.subtotal, $.VATRate),
	taxAmountFormatted: format($.taxAmount, 'c', 'da-DK'),

	// The global total is the sum of the subtotal and the tax amount.
	total: add($.subtotal, $.taxAmount),
	totalFormatted: format($.total, 'c', 'da-DK'),

	terms: template(datasource('TermsAndConditions', 'level', 'termsAndConditions').id, get_stage_id(), `{}`)

}

This transformation yields the following data, that you can also paste into your sample data if you wish to try setting up the template before working on the transformation.

{
  "clientInfo": {
    "contactPersons": [
      "Jane Doe",
      "John Doe"
    ],
    "businessName": "Acme Corporation",
    "addressLine1": "Main Street 1",
    "addressLine2": "Anytown 10000, Ruritania"
  },
  "companyInfo": {
    "contactPerson": "Jill Doe",
    "businessName": "Contoso",
    "addressLine1": "High Street 1",
    "addressLine2": "Anycity 1000, Atlantis"
  },
  "companyWebsite": "http://www.example.com/",
  "logo": "https://stsharedocumotor001.blob.core.windows.net/public-documentation/SalesQuote/logoipsum-216.png",
  "currentDate": "November 20, 2023",
  "VATRate": 0.25,
  "categories": [
    {
      "category": "Chairs",
      "products": [
        {
          "category": "chairs",
          "SKU": 3,
          "name": "Comfy",
          "noOfUnits": "6",
          "unitRate": 599,
          "image": "https://stsharedocumotor001.blob.core.windows.net/public-documentation/SalesQuote/ComfyChair.jpeg",
          "__index": 0,
          "total": 3594,
          "totalFormatted": "3.594,00 kr.",
          "unitRateFormatted": "599,00 kr."
        }
      ],
      "subtotal": 3594,
      "subtotalFormatted": "3.594,00 kr.",
      "taxAmount": 898.50,
      "taxAmountFormatted": "898,50 kr.",
      "total": 4492.50,
      "totalFormatted": "4.492,50 kr."
    },
    {
      "category": "Sofas",
      "products": [
        {
          "category": "sofas",
          "SKU": 1,
          "name": "Blue",
          "noOfUnits": "3",
          "unitRate": 2999,
          "image": "https://stsharedocumotor001.blob.core.windows.net/public-documentation/SalesQuote/BlueSofa.jpeg",
          "__index": 0,
          "total": 8997,
          "totalFormatted": "8.997,00 kr.",
          "unitRateFormatted": "2.999,00 kr."
        },
        {
          "category": "sofas",
          "SKU": 2,
          "name": "Yellow",
          "noOfUnits": "2",
          "unitRate": 3499,
          "image": "https://stsharedocumotor001.blob.core.windows.net/public-documentation/SalesQuote/YellowSofa.jpeg",
          "__index": 1,
          "total": 6998,
          "totalFormatted": "6.998,00 kr.",
          "unitRateFormatted": "3.499,00 kr."
        }
      ],
      "subtotal": 15995,
      "subtotalFormatted": "15.995,00 kr.",
      "taxAmount": 3998.75,
      "taxAmountFormatted": "3.998,75 kr.",
      "total": 19993.75,
      "totalFormatted": "19.993,75 kr."
    }
  ],
  "subtotal": 19589,
  "subtotalFormatted": "19.589,00 kr.",
  "taxAmount": 4897.25,
  "taxAmountFormatted": "4.897,25 kr.",
  "total": 24486.25,
  "totalFormatted": "24.486,25 kr.",
  "terms": "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"
}

Bindings

After defining the data transformation, the bindings are rather straightforward. Feel free to generate the document as you go to keep track on your progress and ease troubleshooting.

Header Image

Let's start with inserting a logo into the header. Select the Picture content control that you inserted earlier and insert one of the Image bindings there. There are five different image bindings in Word: Fill Image, Fit Image, Raw Fill Image, Raw Fit Image or Stretch Image. Feel free to use the one that you like the most - in any case, set the Binding key to logo.

Contact Persons Repeat

  1. Select the [Contact Persons] placeholder.
  2. Add a repeat binding with contactPersons as the binding key, and , as the separator. The content inside the repeat binding will be repeated once for each element of contactPersons, with the scope set to the nth element of the array in the nth repetition. If you generate a document at this point, the result will at this point be something like [Contact Persons], [ContactPersons]. However, the next step is needed to create a meaningful result.
  3. Add a Field binding fetching the entire current scope inside the repeat binding, still surrounding the [Contact Persons] placeholder. This yields the entire first element in the first repetition and the entire second element in the second repetition, listing all the names, i.e., Jane Doe, John Doe.

Client and company Fields

As in the previous guides, insert the Field bindings around all the placeholders preceding the [Product type] heading.

Table Repeats

Remember that each product type needs to be in its own table, with a heading of its own. Therefore, the first Repeat binding needs to enclose the title and the body of the table.

  1. Select the title and the body of a table.
  2. Insert a Repeat binding with the Binding key set to categories.
  3. Insert a Field binding around the title of the table, with the Binding key set to category. Notice that the scope that the title received is equal to the first element of the categories array.
  4. Insert the second Repeat binding, this time around the first row of the table following the column names, with the Binding key set to products.
    1. Inside the row, insert an Image binding into the first column, choosing the Binding key image.
    2. Then insert the appropriate Field bindings into matching placeholders in that row.
  5. Insert the subtotal, taxAmount and total Fields into the last rows of the table. Note that the Binding Editor view is simplified and some of the table cells will not show in the final document.

If you're struggling to completely nail the look of the table, check out what the final document is supposed to look like from inside the template editor.

Locked

Select the entire table with the title, encompassing the newly created Repeat binding, and create a Locked binding with the binding key total. In this way, the table will be locked for editing as soon as the total price is greater than zero.

Totals

Add the totals after the table by inserting Field bindings with appropriate Binding keys.

Terms and Conditions

  1. Select the [TermsAndConditions] placeholder.
  2. Insert a TextElement binding.
  3. Set the Binding key to terms, the property that we created in the transformation.

Website link

  1. Select the Visit our website text in the footer.
  2. Add the Hyperlink binding.
  3. Set companyWebsite as the binding key.

Final document

After this, hopefully, you've recreated the example document. The template should look somewhat like this:

The final template

The final template

It might seem like a long setup for a single document, but this process is now automated permanently, and data sets with any number of products and categories would not pose a problem.

This is a high complexity document, and it is normal to encounter difficulties. Consult our reference pages for Word bindings and data transformations if you would like additional info on anything that was used in the guide. If you would still like to learn more, contact us directly.