{
  "name": "W14 - Purchase Order Processor & Approval Workflow",
  "nodes": [
    {
      "parameters": {
        "content": "## \ud83d\udce6 Purchase Order Processor\n\n### What this workflow does\n1. Watches Gmail for PO attachments\n2. Extracts vendor, line items, totals\n3. Calculates approval level by amount\n4. Logs to Google Sheets tracker\n5. Sends Slack notification with details\n\n### Setup steps\n1. Get PDF Vector API key from pdfvector.com/api-keys\n2. Connect Gmail account\n3. Create Google Sheet with columns (see template)\n4. Connect Slack and set channel\n\n### Approval Thresholds\n- < $1,000: Auto-approve\n- $1,000-$4,999: Manager\n- $5,000-$24,999: Director\n- \u2265 $25,000: VP/CFO\n\n### Perfect for\n- Procurement teams\n- Finance departments\n- Operations managers",
        "height": 480,
        "width": 340,
        "color": 5
      },
      "id": "sticky-main",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -260,
        60
      ]
    },
    {
      "parameters": {
        "content": "## \u2705 Auto Validation\n\n- Approval level by amount\n- Urgency by delivery date\n- Line item totals\n- Missing field handling",
        "height": 160,
        "width": 220
      },
      "id": "sticky-validation",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        528,
        60
      ]
    },
    {
      "parameters": {
        "content": "## \ud83d\udccb Extracted Fields\n\n- PO Number\n- Vendor details\n- Ship-to address\n- Line items array\n- Subtotal, tax, shipping\n- Grand total\n- Payment terms",
        "height": 200,
        "width": 220
      },
      "id": "sticky-fields",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        280,
        60
      ]
    },
    {
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "filters": {
          "includeSpamTrash": false
        }
      },
      "id": "gmail-trigger",
      "name": "Gmail Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "typeVersion": 1,
      "position": [
        100,
        300
      ],
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "messageId": "={{ $json.id }}",
        "simple": false,
        "options": {
          "dataPropertyAttachmentsPrefixName": "attachment_",
          "downloadAttachments": true
        }
      },
      "id": "gmail-get",
      "name": "Get a message",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.2,
      "position": [
        280,
        300
      ],
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "extract",
        "inputType": "file",
        "prompt": "Extract purchase order data as flat fields. poNumber, orderDate (YYYY-MM-DD), requiredDate (YYYY-MM-DD), vendorName, vendorAddress, vendorContact, vendorEmail, vendorPhone, shipToName, shipToAddress, shipToAttention, billToName, billToAddress, lineItemsList (semicolon-separated formatted as: qty x description @ unitPrice = total), lineItemCount (number), subtotal (number), shippingCost (number), tax (number), grandTotal (number), paymentTerms, shippingMethod, notes.",
        "schema": "{\"type\": \"object\", \"properties\": {\"poNumber\": {\"type\": \"string\"}, \"orderDate\": {\"type\": \"string\"}, \"requiredDate\": {\"type\": \"string\"}, \"vendorName\": {\"type\": \"string\"}, \"vendorAddress\": {\"type\": \"string\"}, \"vendorContact\": {\"type\": \"string\"}, \"vendorEmail\": {\"type\": \"string\"}, \"vendorPhone\": {\"type\": \"string\"}, \"shipToName\": {\"type\": \"string\"}, \"shipToAddress\": {\"type\": \"string\"}, \"shipToAttention\": {\"type\": \"string\"}, \"billToName\": {\"type\": \"string\"}, \"billToAddress\": {\"type\": \"string\"}, \"lineItemsList\": {\"type\": \"string\"}, \"lineItemCount\": {\"type\": \"number\"}, \"subtotal\": {\"type\": \"number\"}, \"shippingCost\": {\"type\": \"number\"}, \"tax\": {\"type\": \"number\"}, \"grandTotal\": {\"type\": \"number\"}, \"paymentTerms\": {\"type\": \"string\"}, \"shippingMethod\": {\"type\": \"string\"}, \"notes\": {\"type\": \"string\"}}, \"additionalProperties\": false}",
        "binaryPropertyName": "attachment_0"
      },
      "id": "pdfvector-extract",
      "name": "PDF Vector - Extract PO",
      "type": "n8n-nodes-pdfvector.pdfVector",
      "typeVersion": 2,
      "position": [
        480,
        300
      ],
      "credentials": {
        "pdfVectorApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const po = ($input.first().json?.data || $input.first().json) || {};\nconst trackingId = `PO-${Date.now().toString(36).toUpperCase()}`;\nconst grandTotal = parseFloat(po.grandTotal) || 0;\nconst subtotal   = parseFloat(po.subtotal)   || 0;\nconst grandTotalFormatted = grandTotal.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2});\n\nlet approvalLevel = 'Auto-Approve';\nif (grandTotal >= 25000)     approvalLevel = 'VP/CFO Approval';\nelse if (grandTotal >= 5000) approvalLevel = 'Director Approval';\nelse if (grandTotal >= 1000) approvalLevel = 'Manager Approval';\n\nlet urgency = 'Normal'; let daysUntilRequired = null;\nif (po.requiredDate) {\n  const req = new Date(po.requiredDate); const today = new Date();\n  daysUntilRequired = Math.ceil((req - today) / (1000*60*60*24));\n  if (daysUntilRequired <= 3) urgency = 'Urgent';\n  else if (daysUntilRequired <= 7) urgency = 'High';\n}\n\nreturn [{ json: {\n  trackingId,\n  poNumber:     po.poNumber     || 'N/A',\n  vendorName:   po.vendorName   || 'N/A',\n  orderDate:    po.orderDate    || 'N/A',\n  requiredDate: po.requiredDate || 'N/A',\n  lineItemCount: parseInt(po.lineItemCount) || 0,\n  lineItemsList: po.lineItemsList || 'N/A',\n  subtotal, grandTotal, grandTotalFormatted,\n  shippingCost: parseFloat(po.shippingCost) || 0,\n  tax:          parseFloat(po.tax)          || 0,\n  approvalLevel, urgency, daysUntilRequired,\n  paymentTerms: po.paymentTerms || 'N/A',\n  processedAt: new Date().toISOString()\n}}];"
      },
      "id": "process-po",
      "name": "Process PO",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "list"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Tracking ID": "={{ $json.trackingId }}",
            "PO Number": "={{ $json.poNumber }}",
            "Vendor": "={{ $json.vendorName }}",
            "Order Date": "={{ $json.orderDate || 'N/A' }}",
            "Required Date": "={{ $json.requiredDate || 'N/A' }}",
            "Line Items": "={{ $json.lineItemCount }}",
            "Subtotal": "={{ $json.subtotal }}",
            "Shipping": "={{ $json.shippingCost || 0 }}",
            "Tax": "={{ $json.tax || 0 }}",
            "Grand Total": "={{ $json.grandTotal }}",
            "Approval Level": "={{ $json.approvalLevel }}",
            "Urgency": "={{ $json.urgency }}",
            "Status": "=Pending Approval",
            "Received Date": "={{ $json.processedAt.split('T')[0] }}"
          },
          "matchingColumns": []
        },
        "options": {}
      },
      "id": "sheets-log",
      "name": "Log to PO Tracker",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        880,
        300
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "YOUR_SLACK_CHANNEL_ID",
          "mode": "list"
        },
        "text": "=\ud83d\udce6 *New Purchase Order Received*\n\n*Tracking:* {{ $('Process PO').item.json.trackingId }}\n*PO Number:* {{ $('Process PO').item.json.poNumber }}\n*Vendor:* {{ $('Process PO').item.json.vendorName }}\n\n\ud83d\udccb *Line Items ({{ $('Process PO').item.json.lineItemCount }}):*\n{{ $('Process PO').item.json.lineItemsList }}\n\n\ud83d\udcb0 *Total:* ${{ $('Process PO').item.json.grandTotalFormatted }}\n\ud83d\udcc5 *Required By:* {{ $('Process PO').item.json.requiredDate }}\n\n\ud83d\udd10 *Approval Required:* {{ $('Process PO').item.json.approvalLevel }}\n\u26a1 *Urgency:* {{ $('Process PO').item.json.urgency }}",
        "otherOptions": {}
      },
      "id": "slack-notify",
      "name": "Notify Procurement",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        1080,
        300
      ],
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Gmail Trigger": {
      "main": [
        [
          {
            "node": "Get a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get a message": {
      "main": [
        [
          {
            "node": "PDF Vector - Extract PO",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PDF Vector - Extract PO": {
      "main": [
        [
          {
            "node": "Process PO",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process PO": {
      "main": [
        [
          {
            "node": "Log to PO Tracker",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to PO Tracker": {
      "main": [
        [
          {
            "node": "Notify Procurement",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": [
    {
      "name": "PDF Vector"
    },
    {
      "name": "Procurement"
    },
    {
      "name": "Finance"
    }
  ],
  "meta": {
    "templateCredsSetupCompleted": false
  }
}