Quality Control and Error Handling Cleaning Up Order States and Holds

When an order requires pausing or special handling, it often enters a "Hold" or "Grover" state. To prevent scheduling conflicts, inaccurate time tracking, and cluttered portals, our automated cleanup logic immediately steps in to reset or reassign these orders.

This page explains exactly what happens behind the scenes when an order is flagged for Hold or routed to Grover, and how the system safely cleans up the associated data.

Routing Logic Overview

Every time an order updates, the system checks the assigned Lead or Staff name. If it detects a special state, it "short-circuits" the standard routing and triggers a dedicated cleanup pipeline.

flowchart TD
    A["Order Update Triggered"] --> B{"Check Assigned Staff"}
    B -- "Hold" --> C["Hold Cleanup Pipeline"]
    B -- "Grover" --> D["Grover Pipeline"]
    B -- "Other Tech" --> E["Standard Time & Routing Logic"]
    
    C --> F["Wipe assignments & reset times"]
    D --> G["Assign to Grover & reset times"]

The Admin Exception
In both the Hold and Grover pipelines, any subitems assigned to Admin are strictly preserved. The system will skip these rows to ensure administrative tasks and billing records remain intact.


1. The Hold Status Pipeline

When an order's lead or staff name is set to Hold, the system completely wipes the slate clean. This ensures no technicians are accidentally dispatched and no time is blocked off on the calendar.

Parent Item Updates

The main order (parent item) is scrubbed of its active routing data:

FieldNew ValuePurpose
Trigger- (Cleared)Stops any pending automations.
InstructionsBlankClears outdated routing notes.
Portal SyncEmptyRemoves the order from technician portals.
ServicesBlankClears Charlie/Service summaries.
Total Mins0Frees up calendar capacity.
Calendar ColorHoldVisually flags the order on the schedule.

Subitem Updates

The system then loops through every service (subitem) attached to the order and applies the following resets:

  1. 1

    Remove Staff Assignments

    The assigned staff member is changed to None.

  2. 2

    Unlock the Row

    The lock status is changed to Unlocked, allowing it to be freely edited or reassigned later.

  3. 3

    Reset Durations

    The calculated minutes for the service are reset to 0.

  4. 4

    Disconnect Portals

    The subitem is removed from all individual technician portals.


2. The Grover Pipeline

"Grover" acts as a special holding or administrative state. When an order is assigned to Grover, the system doesn't just wipe the data—it actively reassigns ownership to the Grover user while resetting time calculations.

Parent Item Updates

FieldNew ValuePurpose
StaffGroverOfficially assigns the parent order.
Trigger- (Cleared)Stops any pending automations.
Portal SyncGrover's IDPushes the order to Grover's specific portal.
Total Mins0Ensures Grover's schedule isn't artificially blocked.
Calendar ColorMatches Deal StageInherits the current Deal Stage color for context.

Subitem Updates

Similar to the Hold pipeline, the system loops through all subitems (ignoring Admins) and routes them to Grover:

  1. 1

    Assign to Grover

    The staff column for the service is explicitly set to Grover.

  2. 2

    Unlock the Row

    The lock status is changed to Unlocked.

  3. 3

    Reset Durations

    The calculated minutes are zeroed out (0).

  4. 4

    Sync to Grover's Portal

    The subitem is linked directly to Grover's portal ID so it appears in their queue.

Need to resume an order?
Simply reassign the parent item from "Hold" or "Grover" to a standard technician (e.g., Matt, Kyle, Derek). The system will automatically exit these short-circuits and recalculate the required square footage, time minimums, and portal syncs.


Technical Reference

For developers maintaining the webhook logic, the cleanup pipelines utilize a short-circuit pattern in the Python execution environment.

Here is a simplified look at how the payload is constructed before being sent as a GraphQL mutation to Monday.com:

# Example: Hold Status Cleanup Payload Construction
if lead_name.lower() == "hold" or parent_staff.lower() == "hold":
    hold_parent_v = {
        COL_TRIGGER: {"label": "-"},
        COL_INSTRUCTIONS: "",
        COL_PORTAL_PARENT: {"item_ids": []},
        COL_CHARLIE_SVCS: "",
        COL_SERVICES_PARENT: "",
        COL_TOTAL_MINS: "0",
        COL_CAL_COLOR: {"label": "Hold"}
    }

    hold_sub_mutations = []
    for h_idx, sub in enumerate(subitems):
        # Skip Admin rows
        if sub_staff.lower() == "admin":
            continue
            
        sub_update = {
            C_SUB_STAFF: {"label": "None"},
            C_SUB_LOCK: {"label": "Unlocked"},
            C_SUB_MINS: "0",
            C_SUB_PORTAL: {"item_ids": []}
        }
        # Append to mutation list...

API Rate Limits
Because these pipelines loop through subitems and generate multiple GraphQL mutations (change_multiple_column_values), large orders with dozens of subitems will consume more API complexity points. The script batches these into a single request where possible to optimize performance.