Document Templates

Socotra’s document rendering engine uses templates written in a language called Liquid, created by Shopify. For more information see the Liquid Language Reference.

Socotra supports a set of custom functions in Liquid, documented here: Socotra Liquid Filters

Templates have names of the form *.template.liquid, and are a combination of HTML and liquid markup that accesses and processes policy data.

Data Available in Templates

All policy information is available in a structure called data.policy. For example, gross premium for the first segment of a policy can be referenced in a document template as data.policy.characteristics[0].gross_premium.

The object hierarchy for data available to the document template is:

{
  "data": {
    "policy": {
      "characteristics": [{
        "tax_groups": [{}]
      }],
      "exposures": [{
        "characteristics": [{}],
        "perils": [{
          "characteristics": [{}]
        }]
      }],
      "modifications": [{
        "exposure_modifications": [{
           "peril_modifications": [{}]
        }]
      }],
      "invoices": [{
        "statuses": [{}],
        "payments": [{}]
      }],
      "fees": [{}]
    },
    "policyholder": {
      "entity": {}
    }
  }
}

Note

See Endorsement Documents and Renewal Documents for data available in templates during Endorsements and Renewals.

Note

When rendering numerical field values, generally you will want to use a filter for formatting; otherwise numbers will be rendered in exponential format. For example, instead of including the expression {{ data.policy.characteristics[0].field_values.annual_miles }}, instead use {{ data.policy.characteristics[0].field_values.annual_miles | format_number_pattern: "0" }}

Details of the data Object

ValuesMaps

Many objects below refer to a “ValuesMap”, which is an implementation of a multimap data structure. A ValuesMap contains key-value pairs where the value can be a single value or an array, depending on whether that field was configured to be repeatable. The ValuesMap for field values is structured like this:

{
  "field1": "value1",
  "field2": ["value2", "value3"]
}

Note

This map is different from the data structures in the API, where all map data structures are key/array pairs.

Field Groups

In the field_values objects below, the value for fields of the group type is an array of locators. The groups of fields themselves are in an object called field_groups_by_locator. That object contains all field groups, not just those for the field in question. Use this example implementation as a starting point. This outputs the accessory_type field from each “accessory” field group:

{% assign exposure_values = data.exposure_characteristics.field_values %}
{% assign exposure_groups = data.exposure_characteristics.field_groups_by_locator %}

{% for accessory_loc in exposure_values.accessory %}
  {% assign accessory = exposure_groups[accessory_loc] %}
  {{accessory.accessory_type}}
{% endfor %}

data.policy

Details of the policy’s child objects are in the following sections.

{
  "locator": string,
  "policyholder_locator": string,
  "product_locator": string,
  "display_id": string,
  "quote_locator": string,
  "quote_name": string,
  "created_timestamp": long,
  "updated_timestamp": long,
  "issued_timestamp": long,
  "gross_fees": number,
  "gross_fees_currency": string,
  "characteristics": [{}],
  "exposures": [{}],
  "modifications": [{}],
  "invoices": [{}],
  "fees": [{}],
  "commissions": [{}],
  "cancellation": {
    "modification_locator": string,
    "modification_name": string,
    "effective_timestamp": long
  },
  "payment_schedule_name": string,
  "original_contract_start_timestamp": string,
  "original_contract_end_timestamp": string,
  "effective_contract_end_timestamp": string
}

data.policyholder

{
  "locator": string,
  "id": string,
  "created_timestamp": long,
  "updated_timestamp": long,
  "entity": {
    "accountLocator": string,
    "entityType": string,
    "values": ValuesMap,
    "subValuesByLocator": map<String, ValuesMap>,
    "createdTimestamp": long,
    "updatedTimestamp": long
  }
}

data.policy Child Objects

data.policy.characteristics

[
  {
    "locator": string,
    "policyholder_locator": string,
    "product_locator": string,
    "start_timestamp": long,
    "end_timestamp": long,
    "gross_premium": number,
    "gross_premium_currency": string,
    "gross_taxes": string,
    "gross_taxes_currency": string,
    "issued_timestamp": long,
    "field_values": ValuesMap,
    "field_groups_by_locator": map<String, ValuesMap>,
    "created_timestamp": long,
    "updated_timestamp": long,
    "tax_groups": [
      {
        "name": string,
        "amount": number,
        "amount_currency": string
      }
    ]
  }
]

data.policy.exposures

[
  {
    "locator": string,
    "name": string,
    "display_id": string,
    "characteristics": [
      {
        "locator": string,
        "policy_locator": string,
        "policyholder_locator": string,
        "product_locator": string,
        "start_timestamp": long,
        "end_timestamp": long,
        "created_timestamp": long,
        "updated_timestamp": long,
        "field_values": ValuesMap,
        "field_groups_by_locator": map<String, ValuesMap>
      }
    ],
    "perils": [
      {
        "locator": string,
        "display_id": string,
        "name": string,
        "characteristics": [
          {
            "locator": string,
            "issued_timestamp": long,
            "exposure_characteristics_locator": string,
            "policy_characteristics_locator": string,
            "indemnity_per_item": number,
            "indemnity_per_event": number,
            "indemnity_in_aggregate": number,
            "lump_sum_payment": number,
            "deductible": number,
            "premium": number,
            "technical_premium": number // Optional
            "coverage_start_timestamp": long,
            "coverage_end_timestamp": long,
            "original_coverage_end_timestamp": long,
            "field_values": ValuesMap,
            "field_groups_by_locator": map<String, ValuesMap>,
            "end_change_bound": long,
            "policy_modification_locator": string,
            "policyholder_locator": string,
            "policy_locator": string,
            "created_timestamp": long,
            "updated_timestamp": long
          }
        ],
        "created_timestamp": long,
        "updated_timestamp": long
      }
    ],
    "created_timestamp": long,
    "updated_timestamp": long
  }
]

data.policy.modifications

[
  {
    "locator": string,
    "name": string,
    "display_id": string,
    "number": integer,
    "issued_timestamp": long,
    "new_policy_characteristics_locator": string,
    "exposure_modifications": [
      {
        "locator": string,
        "new_exposure_characteristics_locator": string,
        "peril_modifications": [
          {
            "locator": string,
            "peril_locator": string,
            "exposure_modification_locator": string,
            "new_peril_characteristics_locator": string,
            "replaced_peril_characteristics_locator": string
          }
        ]
      }
    ],
    "created_timestamp": long,
    "updated_timestamp": long
  }
]

data.policy.invoices

[
  {
    "locator": string,
    "type": string,
    "display_id": string,
    "created_timestamp": long,
    "updated_timestamp": long,
    "number": integer,
    "current_status": string,
    "statuses": [
      {
        "status": string,
        "timestamp": long,
        "account_locator": string
      }
    ],
    "due_timestamp": long,
    "total_due": number,
    "total_due_currency": string,
    "payments": [
      {
        "payment_locator": string,
        "amount": number,
        "timestamp": long
      }
    ]
  }
]

data.policy.fees

[
  {
    "name": string,
    "amount": number,
    "amount_currency": string,
    "description": string
  }
]

data.policy.commissions

[
  {
    "peril_characteristics_locator": string,
    "peril_commissions": [{}]
  }
]

data.policy.commissions.peril_commissions

[
  {
    "amount": number,
    "amount_currency": string,
    "recipient": string
  }
]

Headers and footers

  • Headers and footers may be added using HTML enclosed in special header and footer blocks.

  • CSS that applies to the rest of the template will not apply to those blocks, so it must be re-applied within each block.

  • If there are multiple header blocks or footer blocks, the contents of each type of block will be concatenated.

Usage

  • Enclose the header HTML in {% header %} and {% endheader %}

  • Enclose the footer HTML in {% footer %} and {% endfooter %}

  • Add page numbers using <span class="page"></span>

  • Add page count using <span class="topage"></span>

Example

{% header %}
    <center>
        <p>This is at the top of page <span class="page"></span></p>
    </center>
{% endheader %}

{% footer %}
    <center>
        <p>Page <span class="page"></span> of
            <span class="topage"></span></p>
    </center>
{% endfooter %}