← Back to Cookbook

Inventory Alert

Checks inventory levels via API, emails when stock hits reorder point.

httpswitchresend

Source

/**
 * Monitors inventory levels via API and alerts when stock is low.
 */

schedule inventory_check {
  label: "Inventory Check"
  cron: "0 8,14,20 * * *"
  timezone: "America/Chicago"
}

secret inventory_config {
  vars: [INVENTORY_API_URL, INVENTORY_API_KEY]
}

graph check_inventory {
  label: "Check Inventory"

  root {
    type: code
    label: "Start"
    code: @ts {
      return { checked_at: new Date().toISOString() }
    }
    outputSchema: @json {
      {
        "type": "object",
        "properties": {
          "checked_at": { "type": "string" }
        }
      }
    }
  }

  node fetch_levels {
    type: http
    label: "Fetch inventory levels"
    url: @ts { return context.secrets.inventory_config.INVENTORY_API_URL + "/levels" }
    headers: @ts {
      return { Authorization: "Bearer " + context.secrets.inventory_config.INVENTORY_API_KEY }
    }
    secrets: {
      inventory_config: [INVENTORY_API_URL, INVENTORY_API_KEY]
    }
  }

  node find_low_stock {
    type: code
    label: "Find low stock items"
    code: @ts {
      const items = context.nodes.fetch_levels.output.items || []
      const low = items.filter(function(item) {
        return item.quantity <= item.reorder_point
      })
      return {
        total_items: items.length,
        low_stock_count: low.length,
        low_stock_items: low,
        has_alerts: low.length > 0
      }
    }
  }

  node route {
    type: switch
    label: "Check if alerts needed"
    cases: ["alert", "ok"]
    router: @ts {
      if (context.nodes.find_low_stock.output.has_alerts) return "alert"
      return "ok"
    }
  }

  node send_alert {
    type: resend
    label: "Send low stock alert"
    from: @ts { return "[email protected]" }
    to: @ts { return "[email protected]" }
    subject: @ts {
      return "Low Stock Alert: " + context.nodes.find_low_stock.output.low_stock_count + " items need reorder"
    }
    text: @ts {
      const items = context.nodes.find_low_stock.output.low_stock_items
      const list = items.map(function(item) {
        return "- " + item.name + ": " + item.quantity + " remaining (reorder at " + item.reorder_point + ")"
      }).join("\n")
      return "The following items are below reorder levels:\n\n" + list
    }
  }

  node log_ok {
    type: code
    label: "Log all clear"
    code: @ts {
      return {
        status: "ok",
        total_items: context.nodes.find_low_stock.output.total_items,
        checked_at: context.nodes.root.output.checked_at
      }
    }
  }

  flow {
    root -> fetch_levels
    fetch_levels -> find_low_stock
    find_low_stock -> route
    route -["alert"]-> send_alert
    route -["ok"]-> log_ok
  }
}

trigger on_inventory_check {
  schedule:inventory_check -> check_inventory
  enabled: true
}

Flow

Trigger → graph

Graph nodes