Sync order timeline comments to the order note, with Mechanic.

Mechanic is an automation development platform for Shopify. :)

Sync order timeline comments to the order note

by Isaac Bowen (team@usemechanic.com)

This task makes order comments more portable, by copying them to the order note during a regular scan (nightly, hourly, or manually). Once copied over, they can be included on printed invoices, or used anywhere you might use the order note.

Runs when a user triggers the task. Configuration includes only scan orders matching this query, comment date format, run daily, and run hourly.

15-day free trial – unlimited tasks

Documentation

This task scans all orders (optionally filtering by the query of your choice), and copies any new timeline comments to the order note. Any existing content in the order note will be preserved; each new comment will be added to the end of the note. Any edited timeline comments will be added as new note lines during the next scan.

Use the "Run task" button to run the scan manually. Or, enable the "Run daily" and/or "Run hourly" options to have Mechanic run this task automatically.

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.

Events
when a user triggers the task (mechanic/user/trigger)
Options
only scan orders matching this query, comment date format (required), run daily (boolean), run hourly (boolean)
Script
{% assign cursor = nil %}
{% assign order_ids_to_scan = array %}

{% for n in (0..10000) %}
  {% capture query %}
    query {
      orders(
        first: 250
        after: {{ cursor | json }}
        sortKey: CREATED_AT
        reverse: true
        query: {{ options.only_scan_orders_matching_this_query | json }}
      ) {
        pageInfo {
          hasNextPage
        }
        edges {
          cursor
          node {
            id
            hasTimelineComment
          }
        }
      }
    }
  {% endcapture %}

  {% assign result = query | shopify %}

  {% assign order_ids_to_scan = result.data.orders.edges | map: "node" | where: "hasTimelineComment", true | map: "id" | concat: order_ids_to_scan %}

  {% if result.data.orders.pageInfo.hasNextPage %}
    {% assign cursor = result.data.orders.edges.last.cursor %}
  {% else %}
    {% break %}
  {% endif %}
{% endfor %}

{% if event.preview %}
  {% assign order_ids_to_scan = '["gid://shopify/Order/1234567890"]' | parse_json %}
{% endif %}

{% for order_id in order_ids_to_scan %}
  {% assign cursor = nil %}
  {% assign order_note_existing = nil %}
  {% assign order_comments = array %}

  {% for n in (0..10000) %}
    {% capture query %}
      query {
        order(
          id: {{ order_id | json }}
        ) {
          name
          note
          events(
            first: 250
            after: {{ cursor | json }}
            query: "verb:comment"
            sortKey: CREATED_AT
          ) {
            pageInfo {
              hasNextPage
            }
            edges {
              node {
                createdAt
                message
              }
            }
          }
        }
      }
    {% endcapture %}

    {% assign result = query | shopify %}

    {% assign order_node = result.data.order %}
    {% assign order_note_existing = order_node.note | strip %}

    {% for event_edge in order_node.events.edges %}
      {% assign event_node = event_edge.node %}

      {% assign order_comment = hash %}
      {% assign order_comment["created_at"] = event_node.createdAt %}
      {% assign order_comment["message"] = event_node.message %}

      {% assign order_comments[order_comments.size] = order_comment %}
    {% endfor %}

    {% if order_node.events.pageInfo.hasNextPage %}
      {% assign cursor = order_node.events.edges.last.cursor %}
    {% else %}
      {% break %}
    {% endif %}
  {% endfor %}

  {% if event.preview %}
    {% assign order_preview_comment = hash %}
    {% assign order_preview_comment["created_at"] = "now" %}
    {% assign order_preview_comment["message"] = "This is a comment that's been left." %}

    {% assign order_comments[0] = order_preview_comment %}
  {% endif %}

  {% assign order_note_lines_existing = order_note_existing | split: newline %}
  {% assign order_note_lines_to_add = array %}

  {% for order_comment in order_comments %}
    {% assign order_comment_found = false %}
    {% for order_note_line in order_note_lines_existing %}
      {% if order_note_line contains order_comment.message %}
        {% assign order_comment_found = true %}
        {% break %}
      {% endif %}
    {% endfor %}

    {% unless order_comment_found %}
      {% capture order_comment_as_note_line %}
        {{ order_comment.created_at | date: options.comment_date_format__required }} - {{ order_comment.message | strip | strip_html | json }} ({{ order_node.name }})
      {% endcapture %}

      {% assign order_note_lines_to_add[order_note_lines_to_add.size] = order_comment_as_note_line | strip %}
    {% endunless %}
  {% endfor %}

  {% if order_note_lines_to_add == empty %}
    {% continue %}
  {% endif %}

  {% assign double_newline = newline | append: newline %}

  {% assign order_note_updated = order_note_lines_to_add | join: double_newline | prepend: double_newline | prepend: order_note_existing | strip %}

  {"log": {"order_id": {{ order_id | json }}, "order_note_existing": {{ order_note_existing | json }}}}

  {% action "shopify" %}
    mutation {
      orderUpdate(
        input: {
          id: {{ order_id | json }}
          note: {{ order_note_updated | json }}
        }
      ) {
        order {
          note
        }
        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.
Defaults
Only scan orders matching this query
status:open
Comment date format
%d/%m/%y