Mechanic is a development and ecommerce automation platform for Shopify. :)
Useful for enforcing order limits on the backend, use this task to ensure that orders with too many of certain products will be automatically cancelled.
Runs Occurs whenever an order is created. Configuration includes skus and quantity cancellation thresholds, email customer when cancelling, refund payment for cancelled orders, restock inventory for cancelled orders, cancellation reason to set, and staff note for timeline.
Useful for enforcing order limits on the backend, use this task to ensure that orders with too many of certain products will be automatically cancelled.
Configure the product SKUs to monitor on the left and the quantities that will trigger a cancellation on the right. Optionally, choose whether to email the customer, refund the payment, or restock the inventory upon cancellation. The configured cancellation reason must be one of - 'customer', 'declined', 'fraud', 'inventory', 'other', or 'staff'.
Notes:
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/create
{% assign skus_and_quantity_cancellation_thresholds = options.skus_and_quantity_cancellation_thresholds__keyval_number_required %} {% assign notify_customer = options.email_customer_when_cancelling__boolean %} {% assign refund_payment = options.refund_payment_for_cancelled_orders__boolean %} {% assign restock_inventory = options.restock_inventory_for_cancelled_orders__boolean %} {% assign cancellation_reason = options.cancellation_reason_to_set | default: "other" %} {% assign staff_note = options.staff_note_for_timeline %} {% assign skus_to_monitor = skus_and_quantity_cancellation_thresholds | keys %} {% 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 order details and line items to tally {% endcomment %} {% capture query %} query { order(id: {{ order.admin_graphql_api_id | json }}) { id name cancelledAt displayFulfillmentStatus lineItems(first: 250) { nodes { sku quantity } } } } {% endcapture %} {% assign result = query | shopify %} {% if event.preview %} {% capture result_json %} { "data": { "order": { "id": "gid://shopify/Order/1234567890", "name": "#PREVIEW", "displayFulfillmentStatus": "UNFULFILLED", "lineItems": { "nodes": [ { "sku": {{ skus_and_quantity_cancellation_thresholds.first.first | json }}, "quantity": {{ skus_and_quantity_cancellation_thresholds.first.last | json }} } ] } } } } {% endcapture %} {% assign result = result_json | parse_json %} {% endif %} {% assign order = result.data.order %} {% if order.cancelledAt %} {% log "This order has already been cancelled." %} {% break %} {% endif %} {% 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 %} -- tally quantities of the configured skus across all line items {% endcomment %} {% assign skus_and_line_item_quantities = hash %} {% for line_item in order.lineItems.nodes %} {% if line_item.sku == blank %} {% continue %} {% endif %} {% if skus_to_monitor contains line_item.sku %} {% assign skus_and_line_item_quantities[line_item.sku] = skus_and_line_item_quantities[line_item.sku] | default: 0 | plus: line_item.quantity %} {% endif %} {% endfor %} {% assign order_qualifies = nil %} {% for keyval in skus_and_line_item_quantities %} {% assign sku = keyval[0] %} {% assign count = keyval[1] %} {% if count >= skus_and_quantity_cancellation_thresholds[sku] %} {% assign order_qualifies = true %} {% break %} {% endif %} {% endfor %} {% unless order_qualifies %} {% break %} {% endunless %} {% log message: "Order qualifies to be cancelled due to having one or more SKUs hit their quantity thresholds.", skus_and_line_item_quantities: skus_and_line_item_quantities, skus_and_quantity_cancellation_thresholds: skus_and_quantity_cancellation_thresholds %} {% 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 %}