Shipment Batch Liquid Form — Field Reference
This article explains how to access data when building or editing a Shipment Batch liquid form. The primary form model is ShipmentBatch. In every Shipment Batch template, the root object is:
{{ shipment_batch }}Shipment Batch forms are used for documents such as batch pick lists, driver manifests, and custom PDFs printed from Logistics → Shipment Batches.
Two layout modes in the default template
The default Shipment Batch form switches layout based on an organization setting:
- Product Pick List — when Show delivery routes on sales orders and invoices is off
- Driver Manifest — when that setting is on
{% assign print_manifest = shipment_batch.internal_organization.setting.show_delivery_routes_on_sales_orders_and_invoices %}
{% if print_manifest %}
{# Driver manifest layout #}
{% else %}
{# Product pick list layout #}
{% endif %}Shipment batch header fields
These fields are available directly on shipment_batch:
| Liquid field | Description | Example |
|---|---|---|
id | Internal database id | {{ shipment_batch.id }} |
name | Batch name (often Load WMT-100 when created from Load Management) | {{ shipment_batch.name }} |
status | Batch status: not requested, requested, processing, finished, errored, cancelled | {{ shipment_batch.status }} |
created_at | When the batch was created | {{ shipment_batch.created_at | format_date }} |
internal_organization | The entity that owns the batch | {{ shipment_batch.internal_organization.practical_name }} |
shipment_batch_items | All batch rows (orders in the batch) | See Looping batch items |
sorted_shipment_batch_items | Batch rows sorted by load_number descending (manifest layout) | See Driver manifest |
orders | All sales orders in the batch | {{ shipment_batch.orders.first.order_number }} |
product_on_picklists | Aggregated pick-list product rows | See Product pick list rows |
freight_load | The Load Management load this batch was created from, if any | See Load Management fields |
Looping batch items
Each row in the batch table is a ShipmentBatchItem. Loop with shipment_batch.shipment_batch_items:
{% for item in shipment_batch.shipment_batch_items %}
Order: {{ item.order.order_number }}
Ship to: {{ item.ship_to_address }}
Pallets: {{ item.number_of_pallets }}
Route load #: {{ item.load_number }}
Stop #: {{ item.stop_number }}
{% endfor %}ShipmentBatchItem fields
| Field | Description |
|---|---|
order | The sales order on this batch row |
ship_to_address | Formatted ship-to address for the order |
number_of_pallets | Number of pallets on this batch row |
load_number | Delivery route load number — not the Load Management load id |
stop_number | Delivery stop number on the manifest |
Important: item.load_number is for driver manifests and route sequencing. It is not the same as a Load Management id such as WMT-100. For Load Management data, use shipment_batch.freight_load.
Order fields (via batch items)
Access the sales order on each row through item.order:
{{ item.order.order_number }}
{{ item.order.order_date | format_date }}
{{ item.order.external_order_reference_number }}
{{ item.order.customer_bill_to.party.company_name }}
{{ item.order.ship_to_party.address_string }}
{{ item.order.route.name }}Standard Versa custom fields on orders use the custom_field_by_name filter:
{{ item.order | custom_field_by_name: 'Driver' }}That filter works for orders, invoices, products, and other standard Versa models. It does not work for Load Management custom fields — see Accessing Load custom fields via additional_attributes below.
Product pick list rows
shipment_batch.product_on_picklists returns an array of rows. Each row is a fixed-position array, not a Product object:
| Index | Meaning |
|---|---|
[0] | Product id |
[1] | Part number / item code |
[2] | Description |
[3] | Warehouse bin location |
[4] | Total picked quantity |
[5] | Comma-separated order numbers |
{% for product_row in shipment_batch.product_on_picklists %}
{% assign product_id = product_row[0] %}
{% assign part_number = product_row[1] %}
{% assign description = product_row[2] %}
{% assign bin = product_row[3] %}
{% assign picked_qty = product_row[4] %}
{% assign order_numbers = product_row[5] %}
<tr>
<td>{{ product_id | product_logo_inline }}</td>
<td>{{ part_number }}</td>
<td>{{ description }}</td>
<td>{{ bin }}</td>
<td>{{ picked_qty }}</td>
</tr>
<tr>
<td colspan="3">Orders: {{ order_numbers }}</td>
</tr>
{% endfor %}Driver manifest example
{% for item in shipment_batch.sorted_shipment_batch_items %}
<tr>
<td>{{ item.load_number }}</td>
<td>{{ item.stop_number }}</td>
<td>{{ item.ship_to_address }}</td>
<td>{{ item.order.customer_bill_to.party.company_name }}</td>
<td>{{ item.order.order_number }}</td>
<td>{{ item.number_of_pallets }}</td>
</tr>
{% endfor %}Load Management fields
When a shipment batch is created from a finalized Load in Load Management, the source load is available as shipment_batch.freight_load.
If the batch was created manually, or the source load was deleted, freight_load is blank. Always guard access:
{% if shipment_batch.freight_load %}
Load ID: {{ shipment_batch.freight_load.display_load_id }}
Manufacturer: {{ shipment_batch.freight_load.manufacturer }}
Distribution center: {{ shipment_batch.freight_load.distribution_center }}
Appointment info: {{ shipment_batch.freight_load.appointment_information }}
Bill of lading #: {{ shipment_batch.freight_load.bill_of_lading_number }}
Shipment status: {{ shipment_batch.freight_load.shipment_status }}
{% endif %}Built-in Load fields (stored as columns)
These are not in additional_attributes. Access them directly on freight_load:
| Field | Description |
|---|---|
display_load_id | User-facing load id (e.g. WMT-100) |
manufacturer | Manufacturer |
distribution_center | Distribution center |
appointment_information | Appointment details |
bill_of_lading_number | Bill of lading number |
shipment_status | Shipment status |
finalized? | Whether the load is finalized |
Accessing Load custom fields via additional_attributes
Firms with Load Management can define extra load fields under:
Setup → Company → Loads → Field definitions
These user-defined fields are not standard Versa CustomField records. They are stored on each load in a JSON object called additional_attributes.
What additional_attributes is
additional_attributes is a key/value object on the load. Each key is the field’s field key from setup. Each value is what the user entered on that load.
Example: if setup defines a field with:
- Label: Dock Door
- Field key:
dock_door
and the user enters Gate 7 on the load, the stored data is conceptually:
{
"dock_door": "Gate 7"
}In Liquid you read that value with:
{{ shipment_batch.freight_load.additional_attributes.dock_door }}How to find the correct field key
- Go to Setup → Company → Loads.
- Open the Field definitions tab.
- Find your field in the list.
- Use the value shown in the Field key column.
Use the field key, not the label.
| Setup label | Field key to use in Liquid | Correct Liquid | Incorrect Liquid |
|---|---|---|---|
| Dock Door | dock_door | {{ freight_load.additional_attributes.dock_door }} | {{ freight_load.additional_attributes['Dock Door'] }} |
| Trailer # | trailer_number | {{ freight_load.additional_attributes.trailer_number }} | {{ freight_load | custom_field_by_name: 'Trailer #' }} |
Basic syntax
On a Shipment Batch form, the load is reached through shipment_batch.freight_load:
{% if shipment_batch.freight_load %}
{{ shipment_batch.freight_load.additional_attributes.dock_door }}
{% endif %}General pattern:
shipment_batch.freight_load.additional_attributes.<field_key>
Replace <field_key> with the exact key from setup, for example:
dock_doorgate_codetrailer_numberseal_number
Assign to a variable first
This is often easier to read and helps when checking for blank values:
{% if shipment_batch.freight_load %}
{% assign dock = shipment_batch.freight_load.additional_attributes.dock_door %}
{% if dock != blank %}
Dock door: {{ dock }}
{% endif %}
{% endif %}Read several custom fields at once
Assign the whole object to a variable, then read multiple keys from it:
{% if shipment_batch.freight_load %}
{% assign load_attrs = shipment_batch.freight_load.additional_attributes %}
Gate code: {{ load_attrs.gate_code }}
Dock door: {{ load_attrs.dock_door }}
Trailer #: {{ load_attrs.trailer_number }}
Seal #: {{ load_attrs.seal_number }}
{% endif %}Print a labeled row only when a value exists
{% if shipment_batch.freight_load %}
{% assign seal = shipment_batch.freight_load.additional_attributes.seal_number %}
{% if seal != blank %}
<tr>
<td><b>Seal #</b></td>
<td>{{ seal }}</td>
</tr>
{% endif %}
{% endif %}Example: show load header with built-in and custom fields together
{% if shipment_batch.freight_load %}
{% assign load = shipment_batch.freight_load %}
{% assign attrs = load.additional_attributes %}
<h2>Load {{ load.display_load_id }}</h2>
<table>
<tr><td>Manufacturer</td><td>{{ load.manufacturer }}</td></tr>
<tr><td>Distribution center</td><td>{{ load.distribution_center }}</td></tr>
<tr><td>Bill of lading #</td><td>{{ load.bill_of_lading_number }}</td></tr>
{% if attrs.dock_door != blank %}
<tr><td>Dock door</td><td>{{ attrs.dock_door }}</td></tr>
{% endif %}
{% if attrs.trailer_number != blank %}
<tr><td>Trailer #</td><td>{{ attrs.trailer_number }}</td></tr>
{% endif %}
</table>
{% endif %}Field type behavior
All values in additional_attributes are stored as strings.
| Field type in setup | What Liquid receives |
|---|---|
| Text | The text entered on the load |
| Number | The number entered, stored as text |
| Date | The date string entered on the load |
| Select | The option value, not the option label shown in the dropdown |
Comments and Suggestions
0 comments
Article is closed for comments.
Related articles