Skip to content

rebecca-king/order-exception-handler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Order Exception Handler

A Python tool that ingests a batch of order exceptions (JSON or CSV), processes each one against a rulebook, and generates ready-to-use operational outputs: Slack alerts, customer email drafts, Gorgias deep links, and a structured results file.


The Business Problem

In omnichannel retail, order exceptions are a constant — inventory drops to zero after an order is placed, a customer types their address in a way the carrier won't accept, a gift note contains content that can't go on a packing slip. Each exception type has a different resolution path and a different team who needs to act on it.

Without a standardised handler, exceptions get triaged manually: someone reads an alert, decides what to do, drafts a message, finds the right Gorgias ticket, and posts to Slack. That process is slow, inconsistent, and easy to miss at volume.

This tool automates the triage layer. Given a file of exceptions, it applies the rulebook for each one — auto-resolving what it can, generating ready-to-send communications for the rest, and routing alerts to the right channel (CX, Ops, or Engineering) so the right person sees exactly what they need to act on.


What It Does

For every exception, the processor outputs:

Output Description
Auto-resolution Action taken automatically (e.g. address abbreviated, characters cleaned, gift note dropped)
Changes log Itemised record of every auto-modification made
Slack alert Fully formatted message ready to post, routed to the correct channel
Customer email draft Pre-written email with order details, product name, and appropriate tone
Gorgias deep link URL that opens a pre-populated new ticket in Gorgias (address and customer comms exceptions)
Order timeline note Internal note to attach to the order record where applicable

Results are written to a structured JSON or CSV file alongside the console summary.


Exception Types Handled

Inventory — Pre-Push

Exceptions raised before the order has been sent to a fulfillment node.

Subtype Resolution
eCommerce Reroute to single node if fulfillable in full → split across 2 nodes if partially available → cancel OOS line, hold receipt, CX Slack + customer email
In-Store iPad push notification sent to store team; store resolves
BOPIS (Buy Online, Pick Up In Store) CX Slack alert asking team to confirm with the guest whether they'll accept home shipment instead of in-store pickup
Endless Aisle Same reroute logic as eCommerce
Ship-From-Store Same reroute logic as eCommerce

Inventory — Post-Push

Exceptions raised after the order has entered the fulfillment pipeline.

  • Ship complete if all units are available
  • Partial ship if some units are available — OOS SKU dropped, order re-pushed, CX Slack + customer email
  • Full OOS — SKU dropped, order re-pushed, CX Slack + customer email

Address Too Long

Carrier systems enforce a 30-character limit per address line. The processor:

  1. Auto-applies standard abbreviations (Boulevard → Blvd, Apartment → Apt, Suite → Ste, and 20+ more)
  2. If the line is within 30 characters after abbreviation — auto-resolved, changes logged
  3. If still over 30 characters — CX Slack alert + Gorgias deep link + customer email asking for a shortened address

Incorrect Address

Address fails validation (unrecognised city, invalid postcode, etc.). Generates a CX Slack alert, a Gorgias deep link, and a pre-drafted customer email asking the customer to confirm or correct their address.

Unsupported Character

Non-ASCII characters in shipping address fields are classified and handled in three ways:

Character type Action
Emoji Auto-dropped
Accented Latin (é, ü, ö, ñ…) Auto-converted to ASCII base character (é → e)
Non-Latin / foreign script Flagged — CX Slack alert + Gorgias deep link + customer email requesting Latin-character address

All auto-changes are logged. If every character was auto-resolvable, the exception is marked resolved with no escalation.

Flagrant Language

Offensive content detected in the gift note field.

  • Gift note is dropped entirely
  • An order timeline note is added: Gift note removed due to content policy
  • No customer outreach is generated

Unknown

Exception type not recognised by the rulebook.

  • Pre-push — routed to #eng-order-exceptions for engineering investigation
  • Post-push — routed to #ops-order-exceptions for CX/Ops manual triage

Order Number Format

Prefix Market
GL1- Domestic
GL2- UK

Project Structure

order-exception-handler/
├── processor.py                    # Main tool
├── sample_exceptions.json          # 11 sample exceptions covering all types
├── sample_exceptions_results.json  # Output generated from sample data
└── README.md

How to Run

Requirements: Python 3.9+, no external dependencies.

# JSON input, default output (writes sample_exceptions_results.json)
python3 processor.py --input sample_exceptions.json

# Specify a Gorgias subdomain (replaces the 'yourstore' placeholder in deep links)
python3 processor.py --input sample_exceptions.json --gorgias-domain mybrand

# Write results to a specific file
python3 processor.py --input sample_exceptions.json --output results.json

# CSV input, CSV output
python3 processor.py --input exceptions.csv --output results.csv

Arguments:

Flag Short Description
--input -i Path to input file (.json or .csv) — required
--output -o Path to output file — optional, defaults to <input>_results.json
--gorgias-domain -g Your Gorgias subdomain (e.g. mybrand for mybrand.gorgias.com)

Input format

Each exception record should include:

{
  "order_number": "GL1-00042381",
  "exception_type": "inventory_pre_push",
  "exception_subtype": "ecom",
  "shipment_status": "pre_push",
  "customer_name": "Jane Smith",
  "customer_email": "jane@example.com",
  "sku": "SKU-001",
  "product_name": "Product Name",
  "quantity_ordered": 2,
  "quantity_available": 0,
  "store_id": null,
  "gift_note": null,
  "shipping_address": {
    "name": "Jane Smith",
    "line1": "123 Main Street",
    "line2": "",
    "city": "Portland",
    "state": "OR",
    "zip": "97201",
    "country": "US"
  },
  "order_total": 120.00,
  "created_at": "2026-04-09T08:00:00Z"
}

exception_subtype is required for inventory_pre_push records. shipment_status (pre_push / post_push) is used to route unknown exceptions to the correct Slack channel.

Output format

Each result record contains:

{
  "order_number": "GL1-00042381",
  "exception_type": "inventory_pre_push",
  "exception_subtype": "ecom",
  "auto_resolved": false,
  "resolution_action": "OOS line cancelled and receipt held. CX Slack alert sent + customer email drafted.",
  "resolution_notes": "Ordered: 2 | Available: 0 — no fulfillment possible.",
  "changes_log": [],
  "effective_address": null,
  "slack_alert": {
    "channel": "#cx-order-exceptions",
    "text": "..."
  },
  "customer_email_draft": {
    "to": "jane@example.com",
    "subject": "An update on your order GL1-00042381",
    "body": "..."
  },
  "gorgias_deep_link": "https://mybrand.gorgias.com/app/ticket/new?...",
  "order_timeline_note": null,
  "processed_at": "2026-04-09T08:00:00+00:00"
}

Configuration

Brand name, support email, and Slack channel names are set as constants at the top of processor.py:

GORGIAS_DOMAIN    = "yourstore"
CX_SLACK_CHANNEL  = "#cx-order-exceptions"
OPS_SLACK_CHANNEL = "#ops-order-exceptions"
ENG_SLACK_CHANNEL = "#eng-order-exceptions"
SUPPORT_EMAIL     = "support@yourstore.com"
BRAND_NAME        = "YourBrand"
ADDRESS_LINE_MAX  = 30

A Note on the Sample Data

sample_exceptions.json contains 11 synthetic records designed to exercise every exception type and resolution path. The data — order numbers, customer names, SKUs, store IDs, and address scenarios — is entirely fictional.

The exception types, routing logic, channel structure, and fulfillment terminology (pre/post push, endless aisle, ship-from-store, BOPIS, node rerouting) are modelled after real commerce operations workflows. The tool is built to reflect how these exceptions are actually handled in practice: what gets auto-resolved, what needs a human, who that human is, and what they need to act.

About

Python tool that processes order exceptions and generates Slack alerts, customer emails, and Gorgias deep links

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages