Mechanic is a development and ecommerce automation platform for Shopify. :)
This task cancels orders as soon as Shopify (or another risk-analysis app) determines it to be high risk. Optionally, this task can also auto-tag the order, email the customer, restock the inventory, and/or refund payment.
Runs Occurs whenever an order is updated. Configuration includes cancellation reason to set, ignore unpaid orders, refund payment for cancelled orders, restock inventory for cancelled orders, email customer when cancelling, staff note for timeline, and add this order tag when cancelling.
This task cancels orders as soon as Shopify (or another risk-analysis app) determines it to be high risk. Optionally, this task can also auto-tag the order, email the customer, restock the inventory, and/or refund payment.
Valid cancellation reasons to set:
NOTE: This task will not cancel orders that have been partially or fully fulfilled
Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Shopifolks, 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.
(By the way, have you seen our documentation? Have you joined the Slack community?)
shopify/orders/updated
{% assign cancellation_reason = options.cancellation_reason_to_set | default: "other" %} {% assign ignore_unpaid_orders = options.ignore_unpaid_orders__boolean %} {% assign refund_payment = options.refund_payment_for_cancelled_orders__boolean %} {% assign restock_inventory = options.restock_inventory_for_cancelled_orders__boolean %} {% assign notify_customer = options.email_customer_when_cancelling__boolean %} {% assign staff_note = options.staff_note_for_timeline %} {% assign order_tag_to_apply = options.add_this_order_tag_when_cancelling %} {% comment %} -- check that a valid cancellation reason has been configured; it will default to 'other' if left blank {% endcomment %} {% assign valid_cancellation_reasons = "customer,declined,fraud,inventory,other,staff" | split: "," %} {% unless valid_cancellation_reasons contains cancellation_reason %} {% error %} {{ "Cancellation reason " | append: cancellation_reason | append: " - must be one of 'customer', 'declined', 'fraud', 'inventory', 'other', or 'staff'." | json }} {% enderror %} {% endunless %} {% comment %} -- get the order statuses and risk assessments {% endcomment %} {% capture query %} query { order(id: {{ order.admin_graphql_api_id | json }}) { id name cancelledAt displayFinancialStatus displayFulfillmentStatus risk { assessments { riskLevel } } } } {% endcapture %} {% assign result = query | shopify %} {% if event.preview %} {% capture result_json %} { "data": { "order": { "id": "gid://shopify/Order/1234567890", "displayFinancialStatus": "PAID", "displayFulfillmentStatus": "UNFULFILLED", "risk": { "assessments": [ { "riskLevel": "NONE" }, { "riskLevel": "HIGH" } ] } } } } {% endcapture %} {% assign result = result_json | parse_json %} {% endif %} {% assign order = result.data.order %} {% log order: order %} {% if order.cancelledAt %} {% log "This order has already been cancelled." %} {% break %} {% endif %} {% if ignore_unpaid_orders and order.displayFinancialStatus != "PAID" %} {% log "This order has not been paid and the ignore unpaid orders option is enabled." %} {% break %} {% endif %} {% comment %} -- get the risk level from each risk assessment {% endcomment %} {% assign order_risk_levels = order.risk.assessments | map: "riskLevel" %} {% unless order_risk_levels contains "HIGH" %} {% log "The current risk assessments for this order do not contain a HIGH risk level." %} {% break %} {% endunless %} {% comment %} -- check to make sure order is unfulfilled to avoid cancellation error {% endcomment %} {% if order.displayFulfillmentStatus == "FULFILLED" or order.displayFulfillmentStatus == "PARTIALLY_FULFILLED" %} {% log "This order has already been fulfilled or partially fulfilled and cannot be cancelled." %} {% break %} {% endif %} {% comment %} -- cancel the order with configured options {% endcomment %} {% action "shopify" %} mutation { orderCancel( orderId: {{ order.id | json }} notifyCustomer: {{ notify_customer | json }} reason: {{ cancellation_reason | upcase }} refund: {{ refund_payment | json }} restock: {{ restock_inventory | json }} staffNote: {{ staff_note | json }} ) { job { id } orderCancelUserErrors { code field message } } } {% endaction %} {% comment %} -- tag the order if there is a tag configured to apply on cancellation {% endcomment %} {% if order_tag_to_apply != blank %} {% action "shopify" %} mutation { tagsAdd( id: {{ order.id | json }} tags: {{ order_tag_to_apply | json }} ) { userErrors { field message } } } {% endaction %} {% endif %}