Swirls

SWIRLS_

  • How it works
  • Pricing

56 matches

OverviewDeliver client operations10Win and grow accounts8Resolve customer issues6Create and distribute content9Run people and operations5Review money and agreements3Monitor systems and data9Compose dependable work6

56 matches

OverviewDeliver client operations10Win and grow accounts8Resolve customer issues6Create and distribute content9Run people and operations5Review money and agreements3Monitor systems and data9Compose dependable work6
← HR & OperationsFormView on GitHub

Expense Report Processor

Validates expense amounts against policy, routes high-value expenses for manager approval.

switchemail

Source

/**
 * Processes expense reports. Validates amounts, checks policy,
 * and routes high-value expenses for manager approval.
 */

form expense_report {
  label: "Expense Report"
  schema: @json {
    {
      "type": "object",
      "required": ["employee_email", "description", "amount", "category"],
      "properties": {
        "employee_email": { "type": "string", "format": "email", "title": "Your Email" },
        "description": { "type": "string", "title": "Description" },
        "amount": { "type": "number", "title": "Amount (USD)" },
        "category": {
          "type": "string",
          "title": "Category",
          "enum": ["travel", "meals", "software", "equipment", "other"]
        },
        "receipt_url": { "type": "string", "title": "Receipt URL" }
      }
    }
  }
}

workflow process_expense {
  label: "Process Expense"

  root {
    type: code
    label: "Extract expense"
    code: @ts { return context.nodes.root.input }
    outputSchema: @json {
      {
        "type": "object",
        "properties": {
          "employee_email": { "type": "string" },
          "description": { "type": "string" },
          "amount": { "type": "number" },
          "category": { "type": "string" },
          "receipt_url": { "type": "string" }
        }
      }
    }
  }

  node check_policy {
    type: code
    label: "Check policy limits"
    code: @ts {
      const expense = context.nodes.root.output
      const limits = { travel: 500, meals: 100, software: 200, equipment: 1000, other: 250 }
      const limit = limits[expense.category] || 250
      const over_limit = expense.amount > limit
      return {
        amount: expense.amount,
        category: expense.category,
        limit: limit,
        over_limit: over_limit,
        needs_approval: expense.amount > 250
      }
    }
  }

  node route {
    type: switch
    label: "Route by amount"
    cases: ["auto_approve", "needs_approval"]
    router: @ts {
      if (context.nodes.check_policy.output.needs_approval) return "needs_approval"
      return "auto_approve"
    }
  }

  node auto_approve {
    type: code
    label: "Auto-approve"
    code: @ts {
      return {
        status: "approved",
        employee: context.nodes.root.output.employee_email,
        amount: context.nodes.root.output.amount,
        category: context.nodes.root.output.category
      }
    }
  }

  node manager_review {
    type: code
    label: "Manager review"
    code: @ts { return {} }
    review: {
      enabled: true
      title: "Expense Approval Required"
      description: "This expense exceeds the auto-approval threshold. See the check_policy node output for the expense details. Submit your decision; the employee is notified either way."
      schema: @json {
        {
          "type": "object",
          "required": ["approved"],
          "properties": {
            "approved": { "type": "boolean", "title": "Approved" },
            "notes": { "type": "string", "title": "Notes" }
          }
        }
      }
      actions: [
        { id: "submit", label: "Submit Decision", outcome: "approve" }
      ]
    }
  }

  node notify_employee {
    type: email
    label: "Notify employee"
    from: @ts { return "[email protected]" }
    to: @ts { return context.nodes.root.output.employee_email }
    subject: @ts { return "Expense report update" }
    text: @ts {
      const expense = context.nodes.root.output
      const review = context.reviews.manager_review || {}
      const decision = review.approved ? "approved" : "denied"
      const notes = review.notes ? "\n\nManager notes: " + review.notes : ""
      return "Your expense report for $" + expense.amount + " (" + expense.category + ") has been " + decision + "." + notes
    }
  }

  flow {
    root -> check_policy
    check_policy -> route
    route -["auto_approve"]-> auto_approve
    route -["needs_approval"]-> manager_review
    manager_review -> notify_employee
  }
}

trigger on_expense {
  form:expense_report -> process_expense
  enabled: true
}

Flow

Trigger to workflow

expense_reportform
process_expense
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

Workflow nodes

CODE
Code Node
Extract expense
CODE
Code Node
Check policy limits
SWITCH
Switch Node
Route by amount
CODE
Code Node
Auto-approve
CODE
Code Node
Manager review
EMAIL
Email Node
Notify employee
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.