Automatically cancel orders with certain risk indicators, with Mechanic.

Mechanic is a development platform for Shopify. :)

Automatically cancel orders with certain risk indicators

This task auto-cancels incoming orders when it finds all of a certain set of risk indicator messages. Risk messages must match exactly, so double-check your configuration!

Runs when an order is updated. Configuration includes required risk indicator messages, cancellation reason, ignore unpaid orders, attempt to void or refund payment for cancelled orders, email customer when cancelling, and add this order tag when cancelling.

15-day free trial – unlimited tasks

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 updated (shopify/orders/updated)
Options
required risk indicator messages (array, required), cancellation reason, ignore unpaid orders (boolean), attempt to void or refund payment for cancelled orders (boolean), email customer when cancelling (boolean), add this order tag when cancelling
Script
{% if event.preview %}
  {% capture order_json %}
    {
      "id": 1234567890,
      "admin_graphql_api_id": "gid://shopify/Order/1234567890",
      "cancelled_at": null,
      "financial_status": "paid",
      "risks": [
        {% for message in options.required_risk_indicator_messages__array_required %}
          {
            "message": {{ message | json }}
          }{% unless forloop.last %},{% endunless %}
        {% endfor %}
      ]
    }
  {% endcapture %}

  {% assign order = order_json | parse_json %}
{% endif %}

{% assign cancellation_reason = options.cancellation_reason | default: "other" %}
{% assign valid_cancellation_reasons = "customer,inventory,fraud,declined,other" | split: "," %}
{% unless valid_cancellation_reasons contains cancellation_reason %}
  {% error %}
    {{ "Cancellation reason " | append: cancellation_reason | append: " - must be one of 'customer', 'inventory', 'fraud', 'declined', or 'other'." | json }}
  {% enderror %}
{% endunless %}

{% assign order_qualifies = true %}

{% if order.cancelled_at != blank %}
  {% assign order_qualifies = false %}
{% elsif options.ignore_unpaid_orders__boolean and order.financial_status == "pending" %}
   {% assign order_qualifies = false %}
{% else %}
  {% assign found_risk_messages = order.risks | map: "message" | sort %}
  {% assign required_risk_messages = options.required_risk_indicator_messages__array_required | sort %}

  {% for message in required_risk_messages %}
    {% unless found_risk_messages contains message %}
      {% assign order_qualifies = false %}
      {% break %}
    {% endunless %}
  {% endfor %}

  {% if found_risk_messages == empty %}
    {% log "This order had no risks. Skipping." %}
  {% elsif order_qualifies == false and found_risk_messages != empty %}
    {% log message: "Found some risk messages, but not all the ones that are required. Skipping.", found_risk_messages: found_risk_messages, required_risk_messages: required_risk_messages %}
  {% endif %}
{% endif %}

{% if order_qualifies %}
  {% if options.attempt_to_void_or_refund_payment_for_cancelled_orders__boolean %}
    {% capture query %}
      query {
        order(id: {{ order.admin_graphql_api_id | json }}) {
          suggestedRefund(suggestFullRefund: true) {
            amountSet {
              shopMoney {
                amount
                currencyCode
              }
            }
          }
        }
      }
    {% endcapture %}

    {% assign result = query | shopify %}

    {% if event.preview %}
      {% capture result_json %}
        {
          "data": {
            "order": {
              "suggestedRefund": {
                "amountSet": {
                  "shopMoney": {
                    "amount": "12.34",
                    "currencyCode": "USD"
                  }
                }
              }
            }
          }
        }
      {% endcapture %}

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

    {% assign suggested_refund = result.data.order.suggestedRefund.amountSet.shopMoney %}
  {% else %}
    {% assign suggested_refund = nil %}
  {% endif %}

  {% action "shopify" %}
    [
      "post",
      "/admin/orders/{{ order.id | json }}/cancel.json",
      {
        {% if suggested_refund %}
          "amount": {{ suggested_refund.amount | json }},
          "currency": {{ suggested_refund.currencyCode | json }},
        {% endif %}
        "reason": {{ cancellation_reason | json }},
        "email": {{ options.email_customer_when_cancelling__boolean | json }}
      }
    ]
  {% endaction %}

  {% if options.add_this_order_tag_when_cancelling != blank %}
    {% action "shopify" %}
      mutation {
        tagsAdd(
          id: {{ order.admin_graphql_api_id | json }}
          tags: {{ options.add_this_order_tag_when_cancelling | json }}
        ) {
          userErrors {
            field
            message
          }
        }
      }
    {% endaction %}
  {% endif %}
{% endif %}
Mechanic tasks are written in Liquid, which makes them easy to write and easy to modify. Learn more about our platform.