Auto-fulfill items that don't require shipping, with Mechanic.

Mechanic is a development and ecommerce automation platform for Shopify. :)

Auto-fulfill items that don't require shipping

Useful for digital products, memberships, or anything else that needs to be fulfilled instantly. This task watches for paid orders, and auto-fulfills all line items that don't require shipping.

Runs when an order is paid. Configuration includes wait until any other shippable items are fulfilled and ignore products with this tag.

15-day free trial – unlimited tasks

Documentation

Useful for digital products, memberships, or anything else that needs to be fulfilled instantly. This task watches for paid orders, and auto-fulfills all line items that don't require shipping.

Optionally, choose to ignore products with a specific tag, and wait until other shippable items are fulfilled, if any.

Developer details

Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Gurus, everybody.

That’s why we make it easy to configure automation without code, why we make it easy to tweak the underlying code once tasks are installed, and why we publish it all here for everyone to learn from.

Open source
View on GitHub to contribute to this task
Events
when an order is paid (shopify/orders/paid)
Options
wait until any other shippable items are fulfilled (boolean), ignore products with this tag
Script
{% comment %}
  Preferred option order:

  {{ options.wait_until_any_other_shippable_items_are_fulfilled__boolean }}
  {{ options.ignore_products_with_this_tag }}
{% endcomment %}

{% capture query %}
  query {
    order(id: {{ order.admin_graphql_api_id | json }}) {
      id
      fulfillmentOrders(
        first: 10
        query: "status:open OR status:in_progress"
      ) {
        edges {
          node {
            id
            assignedLocation {
              location {
                id
              }
            }
            lineItems(first: 30) {
              edges {
                node {
                  id
                  remainingQuantity
                  lineItem {
                    requiresShipping
                    product {
                      tags
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
{% endcapture %}

{% assign result = query | shopify %}

{% if event.preview %}
  {% capture result_json %}
    {
      "data": {
        "order": {
          "id": "gid://shopify/Order/1234567890",
          "fulfillmentOrders": {
            "edges": [
              {
                "node": {
                  "id": "gid://shopify/FulfillmentOrder/1234567890",
                  "assignedLocation": {
                    "location": {
                      "id": "gid://shopify/Location/1234567890"
                    }
                  },
                  "lineItems": {
                    "edges": [
                      {
                        "node": {
                          "id": "gid://shopify/FulfillmentOrderLineItem/1234567890",
                          "remainingQuantity": 1,
                          "lineItem": {
                            "requiresShipping": false
                          }
                        }
                      },
                      {
                        "node": {
                          "id": "gid://shopify/FulfillmentOrderLineItem/2345678901",
                          "remainingQuantity": 2,
                          "lineItem": {
                            "requiresShipping": false,
                            "product": {
                              "tags": [
                                {{ options.ignore_products_with_this_tag | json }}
                              ]
                            }
                          }
                        }
                      }
                    ]
                  }
                }
              },
              {
                "node": {
                  "id": "gid://shopify/FulfillmentOrder/3456789012",
                  "assignedLocation": {
                    "location": {
                      "id": "gid://shopify/Location/3456789012"
                    }
                  },
                  "lineItems": {
                    "edges": [
                      {
                        "node": {
                          "id": "gid://shopify/FulfillmentOrderLineItem/3456789012",
                          "remainingQuantity": 0,
                          "lineItem": {
                            "requiresShipping": true
                          }
                        }
                      }
                    ]
                  }
                }
              }
            ]
          }
        }
      }
    }
  {% endcapture %}

  {% assign result = result_json | parse_json %}
{% endif %}

{% assign order = result.data.order %}
{% assign fulfillment_orders = order.fulfillmentOrders.edges | map: "node" %}

{% if fulfillment_orders == blank %}
  {% log "There are no open fulfillment orders to fulfill on this order." %}
  {% break %}
{% endif %}

{% comment %}
  NOTE: fulfillments can only be created for one location at a time, so need to group fulfillment orders by location
{% endcomment %}

{% assign fulfillment_orders_by_location = hash %}
{% assign has_unfulfilled_shippable_items = nil %}

{% for fulfillment_order in fulfillment_orders %}
  {% assign fulfillment_order_data = hash %}
  {% assign fulfillment_order_data["fulfillment_order_id"] = fulfillment_order.id %}

  {% assign fulfillment_order_line_items = fulfillment_order.lineItems.edges | map: "node" %}

  {% for fulfillment_order_line_item in fulfillment_order_line_items %}
    {% if options.ignore_products_with_this_tag != blank %}
      {% if fulfillment_order_line_item.lineItem.product.tags contains options.ignore_products_with_this_tag %}
        {% continue %}
      {% endif %}
    {% endif %}

    {% if fulfillment_order_line_item.remainingQuantity > 0 %}
      {% if fulfillment_order_line_item.lineItem.requiresShipping %}
        {% assign has_unfulfilled_shippable_items = true %}

      {% else %}
        {% assign fulfillment_order_data["unfulfilled_line_items"]
          = fulfillment_order_data["unfulfilled_line_items"]
          | default: array
          | push: fulfillment_order_line_item
        %}
      {% endif %}
    {% endif %}
  {% endfor %}

  {% if fulfillment_order_data.unfulfilled_line_items != blank %}
    {% assign fulfillment_orders_by_location[fulfillment_order.assignedLocation.location.id]
      = fulfillment_orders_by_location[fulfillment_order.assignedLocation.location.id]
      | default: array
      | push: fulfillment_order_data
    %}
  {% endif %}
{% endfor %}

{% if options.wait_until_any_other_shippable_items_are_fulfilled__boolean and has_unfulfilled_shippable_items %}
  {% log "Unfulfilled shippable items exist on this order and the 'Wait until any other shippable items are fulfilled' option is checked; no auto fulfillments will be made in this task run." %}
  {% break %}
{% endif %}

{% for keyval in fulfillment_orders_by_location %}
  {% action "shopify" %}
    mutation {
      fulfillmentCreateV2(
        fulfillment: {
          lineItemsByFulfillmentOrder: [
            {% for fulfillment_order_data in keyval[1] %}
              {
                fulfillmentOrderId: {{ fulfillment_order_data.fulfillment_order_id | json }}
                fulfillmentOrderLineItems: [
                  {% for unfulfilled_line_item in fulfillment_order_data.unfulfilled_line_items %}
                    {
                      id: {{ unfulfilled_line_item.id | json }}
                      quantity: {{ unfulfilled_line_item.remainingQuantity }}
                    }
                  {% endfor %}
                ]
              }
            {% endfor %}
          ]
          notifyCustomer: false
        }
      ) {
        fulfillment {
          id
          status
        }
        userErrors {
          field
          message
        }
      }
    }
  {% endaction %}
{% endfor %}
Mechanic tasks are written in Liquid, which makes them easy to write and easy to modify. Learn more about our platform.