Skip to main content

Split Packing Slip by Fulfillments

Exaplains how you can edit your existing Packing slip to show a new document for each fulfillment, and includes a temaplate sample.

David Rosero avatar
Written by David Rosero
Updated over 3 weeks ago

Shopify's Packing slips will print a separate slip for each fulfillment, but since our app works differently, this option isn't offered by default in Order Printer Pro.

However, we can create a document that prints each fulfillment as a Separate Packing slip, similar to Shopify's default Packing slip button. To accomplish that, we’ll have to loop through all fulfillment objects. If there is only one fulfillment, a single packing slip will appear.


Instructions

This is a slightly different version of the template code attached at the end of the page.

  1. Find the opening template tag that contains all the Packing Slip contents. You can spot it with the words “class="template-”:

  2. Contract the entire <div class="template-000000"> tag, and surround it with the following fulfillment loop:

    {% for fulfillment in fulfillments %}
    {% assign name = fulfillment.name %}
    {% assign created_at = fulfillment.created_at %}

    <!-- Packing Slip Contents -->

    {% else %}
    <div class="order-table">
    <div class="order-table-row order-table-body">
    <p>{{ TEXT_order }} {{ name }}</p>
    <p>{{ TEXT_no_items_fulfilled }}</p>
    </div>
    </div>
    {% endfor %}

  3. Now, inside the template contents, find the line:

    {% for line_item in line_items %}

    And replace it with:

    {% for line_item in fulfillment.line_items %}

  4. Finally, you must add the following CSS rule inside the style tag.

      .template-000000:not(:first-of-type) {
    page-break-before: always;
    }


    Note: Make sure to replace the “template-00000” class with your template’s value.

  5. As a bonus, you may add this paragraph in the order details, which will display the fulfillment “index”:

      <p>
    <b>Fulfillment {{forloop.rindex}} of {{forloop.length}}</b>
    </p>


Sample Template

We've created a sample template that you can paste into your Order Printer Pro app, displaying a separate slip for each fulfillment in an order. You may copy the one on the bullet below or download the attached file; it's the same code.

Split Packing Slip code

<!-- PACKING SLIP -->

<!-- Document Settings -->
{% assign SETTING_shop_logo = shop_logo_url %} <!-- Logo uploaded from "Templates" page > "Customize Branding" -->
{% assign SETTING_shop_logo_width = shop_logo_width %} <!-- Logo width from "Templates" page > "Customize Branding" -->
{% assign SETTING_shop_accent_color = shop_accent_color %} <!-- Accent color from "Templates" page > "Customize Branding" -->
{% assign SETTING_date_format = "%b %e, %Y" %} <!-- Adjusts date format used, see: https://shopify.github.io/liquid/filters/date/ -->
{% assign SETTING_show_product_images = true %} <!-- Display product images? (true/false) -->
{% assign SETTING_product_image_size = 58 %} <!-- Adjusts size of product images -->
{% assign SETTING_show_cart_attributes = false %} <!-- Display custom information collected during checkout? (true/false) - Example: Pickup/Delivery date & time. See: http://help.forsbergplustwo.com/en/articles/3825760 -->
{% assign SETTING_show_order_number_barcode = true %} <!-- Display a barcode of the order number? (true/false) -->
{% assign SETTING_show_product_barcodes = false %} <!-- Display a barcode of the product variant? (true/false) -->
{% assign SETTING_use_latest_fulfillment = false %} <!-- Display only items from the latest fulfillment? (true/false) - Useful for partial fulfillments where you fulfill first, then print documents -->
{% assign SETTING_move_qty_column_to_left = false %} <!-- Move Qty column to the left side? (true/false) -->

<!-- Shop info -->
{% assign shop_name_text = "" %} <!-- Overwrite the default shop name shown. Leave blank to use default from Shopify -->
{% assign shop_address_text = "" %} <!-- Overwrite the default shop address shown. Leave blank to use default from Shopify -->
{% assign shop_tax_number_text = "" %} <!-- Display your shop tax or VAT number. Example "VAT No. DK12345" -->


<!--
TRANSLATE TEXT / CHANGE WORDING
You can translate or change wording in the document by updating
the words below. Only change the words between the quotes "".
See: http://help.forsbergplustwo.com/en/articles/5137649
-->

{% assign TEXT_order = "Order" %}
{% assign TEXT_shipping_address = "Shipping address" %}
{% assign TEXT_customer = "Customer" %}
{% assign TEXT_tel = "Tel." %}
{% assign TEXT_no_customer_information = "No customer information" %}
{% assign TEXT_payment_method = "Payment method" %}
{% assign TEXT_shipping_method = "Shipping method" %}
{% assign TEXT_pickup_date_and_time = "Pickup on" %}
{% assign TEXT_pickup_location = "Pickup location" %}
{% assign TEXT_delivery_date_and_time = "Delivery on" %}
{% assign TEXT_items = "Items" %}
{% assign TEXT_qty = "Qty" %}
{% assign TEXT_sku = "SKU: " %}
{% assign TEXT_qty_of = "of" %}
{% assign TEXT_no_items_fulfilled = "No items have been fulfilled for this order" %}
{% assign TEXT_notes = "Notes" %}
{% assign TEXT_thanks = "Thank you for shopping with us!" %}


<!-- BEGIN: Latest fulfilled items snippet -->
{% if SETTING_use_latest_fulfillment == true %}
{% assign name = latest_fulfillment.name %}
{% assign created_at = latest_fulfillment.created_at %}
{% assign line_items = latest_fulfillment.line_items %}
{% endif %}
<!-- END: Latest fulfilled items snippet -->


<div class="template-000000">
{% for fulfillment in fulfillments %}
{% assign name = fulfillment.name %}
{% assign created_at = fulfillment.created_at %}

<!-- Packing Slip Contents -->
<div class="header">
<div class="shop-title to-uppercase">
{% if SETTING_shop_logo != blank %}
{{ SETTING_shop_logo | img_tag: '', 'shop-logo'}}
{% else %}
{{ shop.name }}
{% endif %}
</div>
<div class="order-title text-align-right">
<p>
{% if SETTING_show_order_number_barcode == true and name != blank %}
<s-barcode type="code128" value="{{ name }}"></s-barcode><br>
{% endif %}
{{ TEXT_order }} {{ name }}
</p>
<p>
{{ created_at | date: SETTING_date_format }}
</p>
</div>
</div>
<div class="customer-addresses">
<div class="shipping-address">
<p class="subtitle-bold to-uppercase">
{{ TEXT_shipping_address }}
</p>
<p class="address-detail">
{% if shipping_address != blank %}
{{ shipping_address.name }}
{% if shipping_address.company != blank %}
<br>
{{ shipping_address.company }}
{% endif %}
<br>
{{ shipping_address.address1 }}
{% if shipping_address.address2 != blank %}
<br>
{{ shipping_address.address2 }}
{% endif %}
{% if shipping_address.city_province_zip != blank %}
<br>
{{ shipping_address.city_province_zip }}
{% endif %}
<br>
{{ shipping_address.country }}
{% if shipping_address.phone != blank %}
<br>
{{ TEXT_tel }} {{ shipping_address.phone }}
{% endif %}
{% endif %}
</p>
</div>
<div class="billing-address">
<p class="subtitle-bold to-uppercase">
{{ TEXT_customer }}
</p>
<p class="address-detail">
{% assign billing_address = billing_address | default: customer.default_address %}
{% if billing_address != blank %}
{{ billing_address.name }}
{% if billing_address.company != blank %}
<br>
{{ billing_address.company }}
{% endif %}
<br>
{{ billing_address.address1 }}
{% if billing_address.address2 != blank %}
<br>
{{ billing_address.address2 }}
{% endif %}
{% if billing_address.city_province_zip != blank %}
<br>
{{ billing_address.city_province_zip }}
{% endif %}
<br>
{{ billing_address.country }}
{% if billing_address.phone != blank %}
<br>
{{ TEXT_tel }} {{ billing_address.phone }}
{% endif %}
{% elsif customer != blank %}
{{ customer.name }}
{% if customer.email != blank %}
<br>
{{ customer.email }}
{% endif %}
{% if customer.phone != blank %}
<br>
{{ TEXT_tel }} {{ customer.phone }}
{% endif %}
{% else %}
{{ TEXT_no_customer_information }}
{% endif %}
</p>
</div>
<div class="order-details">
{% if shipping_method != blank or fulfillment.tracking_company != blank %}
<p class="subtitle-bold to-uppercase">
{{ TEXT_shipping_method }}
</p>
<p class="order-detail">
{% if fulfillment.tracking_company == blank or fulfillment.tracking_company == "Other" %}
{{ shipping_method.title }}
<br>
{{ fulfillment.tracking_number }}
{% else %}
{{ fulfillment.tracking_company }} {{ shipping_method.title }}
<br>
{{ fulfillment.tracking_number }}
{% endif %}
</p>
{% endif %}
{% if attributes.Pickup-Date != blank or attributes.Delivery-Date != blank %}
{% include "pickup_and_delivery" %}
{% endif %}
<p>
<b>Fulfillment {{forloop.rindex}} of {{forloop.length}}</b>
</p>

</div>
</div>

<hr>

<div class="order-table">
<div class="order-table-row order-table-header">
<div class="order-table-cell item-image-and-description subtitle-bold to-uppercase">
{{ TEXT_items }}
</div>
<div class="order-table-cell item-quantity text-align-right subtitle-bold to-uppercase">
{{ TEXT_qty }}
</div>
</div>

{% comment %}
These variables make sure your images print at high quality.
{% endcomment %}
{% assign resolution_adjusted_size = SETTING_product_image_size | times: 200 | divided_by: 72 | ceil %}
{% capture effective_image_dimensions %}{{ resolution_adjusted_size }}x{{ resolution_adjusted_size }}{% endcapture %}

{% for line_item in fulfillment.line_items %}
{% if line_item.fulfillment_quantity < 1 %}{% continue %}{% endif %}
<div class="order-table-row order-table-body">
{% if SETTING_show_product_images == true %}
<div class="order-table-cell item-image">
<div class="aspect-ratio aspect-ratio-square" style="width: {{ SETTING_product_image_size }}px; height: {{ SETTING_product_image_size }}px;">
{% if line_item.image != blank %}
{{ line_item.image | img_url: effective_image_dimensions | img_tag: '', 'aspect-ratio__content' }}
{% else %}
{{ '/product_image_placeholder.svg' | img_tag: '', 'aspect-ratio__content placeholder' }}
{% endif %}
</div>
</div>
{% endif %}
<div class="order-table-cell item-description">
<p>
<span class="item-description-line">
{{ line_item.product_title }}
</span>
{% if line_item.variant_title != blank %}
<span class="item-description-line">
{{ line_item.variant_title }}
</span>
{% endif %}
{% if line_item.sku != blank %}
<span class="item-description-line">
{{ TEXT_sku }}{{ line_item.sku }}
</span>
{% endif %}
{% for p in line_item.properties %}
{% assign p_internal = p.first | slice: 0 %}
{% unless p.first contains "builder_id" or p.first contains "builder_info" or p.first contains "master_builder" or p_internal == "_" or p.last == "" or p.last == blank %}
{% if p.last contains "/uploads/" or p.last contains "cdn.shopify.com" %}
<span class="item-description-line"><a href="{{ p.last }}" target="_blank">{{ p.first }}</a></span>
{% else %}
<span class="item-description-line">{{ p.first }}: {{ p.last }}</span>
{% endif %}
{% endunless %}
{% endfor %}

{% if SETTING_show_product_barcodes == true and line_item.variant.barcode != blank %}
<s-barcode type="code128" value="{{ line_item.variant.barcode }}"></s-barcode>
{% endif %}
</p>
</div>
<div class="order-table-cell item-quantity text-align-right">
{{ line_item.fulfillment_quantity }} {{ TEXT_qty_of }} {{ line_item.quantity | minus: line_item.refunded_quantity }}
</div>
</div>
{% else %}
<div class="order-table-row order-table-body">
<p>{{ TEXT_no_items_fulfilled }}</p>
</div>
{% endfor %}

</div>

<hr>
<div class="notes-and-pricing">
<div class="notes">
{% if note != blank %}
<div class="notes-row">
<div class="notes-title subtitle-bold to-uppercase">
{{ TEXT_notes }}
</div>
<div class="notes-details">
{{ note | escape | newline_to_br }}
</div>
</div>
{% endif %}
{% if SETTING_show_cart_attributes == true %}
{% for attribute in attributes %}
<div class="notes-row">
<div class="notes-title subtitle-bold to-uppercase">
{{ attribute.first | escape }}:
</div>
<div class="notes-details">
{{ attribute.last | escape }}
</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>

<div class="footer">
<p>
{{ TEXT_thanks }}
</p>
<p>
<strong>
{% if shop_name_text != blank %}
{{ shop_name_text }}
{% else %}
{{ shop.name }}
{% endif %}
</strong>
<br>
{% if shop_address_text != blank %}
{{ shop_address_text }}
{% else %}
{% if shop.address1 != blank %}{{ shop.address1 }},{% endif %}{% if shop.address2 != blank %} {{ shop.address2 }},{% endif %}{% if shop.city != blank %} {{ shop.city }},{% endif %}{% if shop.province_code != blank %} {{ shop.province_code }},{% endif %}{% if shop.zip != blank %} {{ shop.zip }},{% endif %} {{ shop.country }}
{% endif %}
{% if shop_tax_number_text != blank %}
<br>{{ shop_tax_number_text }}
{% endif %}

<br>
<a href="mailto:{{ shop.customer_email }}" target="_blank">{{ shop.customer_email }}</a>
<br>
<a href="https://{{ shop.domain }}" target="_blank">{{ shop.domain }}</a>
</p>
</div>
{% else %}
<div class="order-table">
<div class="header">
<div class="shop-title to-uppercase">
{% if SETTING_shop_logo != blank %}
{{ SETTING_shop_logo | img_tag: '', 'shop-logo'}}
{% else %}
{{ shop.name }}
{% endif %}
</div>
<div class="order-title text-align-right">
<p>
{% if SETTING_show_order_number_barcode == true %}
<img class="barcode" data-barcode="{{ name }}"/><br>
{% endif %}
{{ TEXT_order }} {{ name }}
</p>
<p>
{{ created_at | date: SETTING_date_format }}
</p>
</div>
</div>
<hr>
<div class="order-table-row order-table-body">
<p>{{ TEXT_no_items_fulfilled }}</p>
</div>
</div>
{% endfor %}

</div>


<style>

.template-000000:not(:first-of-type) {
page-break-before: always;
}

.template-000000 * {
font-family: "Open Sans", sans-serif !important;
font-size: 14px;
font-weight: 300;
line-height: 18px;
box-sizing: border-box;
}

.template-000000 {
margin: auto;
padding: 10px 30px 0 30px;
min-height: 600px;
}

.template-000000 p {
margin: 0 0 7px 0;
}

.template-000000 a,
.template-000000 a:link,
.template-000000 a:visited {
color: #000;
font-weight: 300;
text-decoration: none;
}

.template-000000 .header {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
display: flex;
flex-direction: row;
align-items: top;
margin-bottom: 30px;
}

.template-000000 .header p {
margin: 0
}

.template-000000 .shop-title {
color: {{ SETTING_shop_accent_color }};
-webkit-box-flex: 6;
-webkit-flex: 6;
flex: 6;
font-size: 30px;
line-height: 32px;
font-weight: 400;
}

.template-000000 .shop-logo {
max-width: {{ SETTING_shop_logo_width }}px;
max-height: 240px;
}

.template-000000 .order-title {
-webkit-box-flex: 4;
-webkit-flex: 4;
flex: 4;
}

.template-000000 .customer-addresses {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
display: flex;
flex-direction: row;
align-items: top;
margin-bottom: 15px;
}

.template-000000 .shipping-address {
flex-grow: 1;
flex-basis: 0;
}

.template-000000 .billing-address {
flex-grow: 1;
flex-basis: 0;
}

.template-000000 .order-details {
text-align: right;
flex-grow: 1;
flex-basis: 0;
margin-bottom: 15px;
}

.template-000000 .address-detail,
.template-000000 .order-detail {
margin: 5px 0 0;
line-height: 1.5;
}

.template-000000 .subtitle-bold {
font-weight: bold;
margin: 0;
font-size: 13px;
}

.template-000000 .order-detail + .subtitle-bold {
margin-top: 15px;
}

.template-000000 .to-uppercase {
text-transform: uppercase;
}

.template-000000 .text-align-right {
text-align: right;
}

.template-000000 .order-table {
display: block;
}

.template-000000 .order-table-row {
display: -webkit-box;
display: -webkit-flex;
display: flex;
flex-direction: row;
align-items: center;
margin: 15px 0;
page-break-inside: avoid;
}

.template-000000 .order-table-header {
margin-bottom: 0;
}

{% if SETTING_show_product_images == true %}
.template-000000 .order-table-header .item-image-and-description {
-webkit-box-flex: 8;
-webkit-flex: 8;
flex: 8;
margin-right: 30px;
}
{% else %}
.template-000000 .order-table-header .item-image-and-description {
-webkit-box-flex: 7;
-webkit-flex: 7;
flex: 7;
}
{% endif %}

.template-000000 .order-table-header .order-table-cell {
white-space: nowrap;
}

.template-000000 .order-table-cell {
-webkit-box-flex: 2;
-webkit-flex: 2;
flex: 2;
margin: 0;
}

.template-000000 .item-image {
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
margin-right: 15px;
min-width: {{ SETTING_product_image_size | default: 0 }}px;
}

.template-000000 .item-description {
-webkit-box-flex: 7;
-webkit-flex: 7;
flex: 7;
}

.template-000000 .item-description-line {
display: block;
margin: 0;
}

.template-000000 .item-description p {
margin: 0;
line-height: 1.5;
}

.template-000000 .item-line-price {
-webkit-box-flex: 3;
-webkit-flex: 3;
flex: 3;
}

.template-000000 .missing-line-items-text {
margin: 15px 0;
padding: 0 7px;
}

.template-000000 .barcode-image {
height: 32px;
display: inline-block;
}

.template-000000 .qrcode-image {
margin-top: 15px;
height: 75px;
display: inline-block;
}

.template-000000 .notes-and-pricing {
width: 100%;
display: -webkit-box;
display: -webkit-flex;
display: flex;
flex-direction: row;
align-items: top;
margin-bottom: 15px;
}

.template-000000 .notes {
flex-grow: 2;
flex-basis: 0;
}

.template-000000 .notes-row {
display: -webkit-box;
display: -webkit-flex;
display: flex;
flex-direction: row;
align-items: top;
margin: 15px 0;
page-break-inside: avoid;
}

.template-000000 .notes-title {
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
}

.template-000000 .notes-details {
-webkit-box-flex: 3;
-webkit-flex: 3;
flex: 3;
margin-right: 30px;
}

.template-000000 .footer {
margin-top: 30px;
text-align: center;
line-height: 1.5;
}

.template-000000 .footer p {
margin: 0;
margin-bottom: 15px;
}
.template-000000 .footer p:last-of_type {
margin-bottom: 0px;
}

.template-000000 hr {
height: 2px;
border-bottom: 2px solid {{ SETTING_shop_accent_color | default: "#e1e1e1" }};
margin: 0;
}

.template-000000 .aspect-ratio {
position: relative;
display: block;
background: #fafbfc;
padding: 0;
}

.template-000000 .aspect-ratio::before {
z-index: 1;
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border: 1px solid rgba(195,207,216,0.3);
}

.template-000000 .aspect-ratio--square {
width: 100%;
padding-bottom: 100%;
}

.template-000000 .aspect-ratio__content {
position: absolute;
max-width: 100%;
max-height: 100%;
display: block;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}


/* BEGIN: Product table column ordering snippet */
.template-000000 .order-table-cell {
order: 2; /* Set default for all columns (same value equals original ordering) */
}
{% if SETTING_move_qty_column_to_left == true %}
.template-000000 .order-table-cell.item-quantity {
order: 1; /* Set quantity column first in ordering */
text-align: left !important;
}
{% endif %}
/* END: Product table column ordering snippet */

</style>

This is the default Order Printer Pro Packing slip template. If you changed the code or have another template, contact our support to review the possibility of making the changes.

Attachment icon
Did this answer your question?