{
  "name": "Invoice OCR -> Google Sheets with Math Audit",
  "nodes": [
    {
      "parameters": {
        "postProcessAction": "read",
        "format": "resolved",
        "options": {
          "allowUnauthorizedCerts": false,
          "downloadAttachments": true
        }
      },
      "id": "inv-email-trigger",
      "name": "IMAP Email - Inbound Invoices",
      "type": "n8n-nodes-base.emailReadImap",
      "typeVersion": 2,
      "position": [200, 300],
      "credentials": {
        "imap": {
          "id": "imap-cred-placeholder",
          "name": "Finance Inbox IMAP"
        }
      }
    },
    {
      "parameters": {
        "binaryPropertyName": "attachment_0"
      },
      "id": "inv-read-pdf",
      "name": "Extract PDF Text",
      "type": "n8n-nodes-base.readPdf",
      "typeVersion": 1,
      "position": [440, 300]
    },
    {
      "parameters": {
        "resource": "chat",
        "operation": "complete",
        "model": "gpt-4o-mini",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a financial document parser. Extract line item details from the invoice text and return a strict JSON object:\n{\n  \"vendor\": string,\n  \"invoice_number\": string,\n  \"invoice_date\": \"YYYY-MM-DD\",\n  \"currency\": string (e.g. \"EUR\", \"USD\", \"TRY\"),\n  \"subtotal\": number,\n  \"vat_amount\": number,\n  \"total_amount\": number,\n  \"line_items_count\": number\n}\nAll amounts must be numeric floats without currency symbols. Return ONLY the JSON object."
            },
            {
              "role": "user",
              "content": "=Invoice Raw Text:\n{{ $json.text }}"
            }
          ]
        },
        "options": {
          "responseFormat": "json_object"
        }
      },
      "id": "inv-llm-parse",
      "name": "OpenAI - Extract Financial Fields",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 1.4,
      "position": [680, 300],
      "credentials": {
        "openAiApi": {
          "id": "openai-cred-placeholder",
          "name": "OpenAI API Account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const raw = $input.first().json.message?.content || $input.first().json;\nlet parsed = {};\ntry {\n  parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;\n} catch (err) {\n  parsed = {};\n}\n\nconst subtotal = Number(parsed.subtotal || 0);\nconst vat = Number(parsed.vat_amount || 0);\nconst total = Number(parsed.total_amount || 0);\n\nconst expectedTotal = Number((subtotal + vat).toFixed(2));\nconst diff = Math.abs(total - expectedTotal);\nconst isMathValid = diff <= 0.05 && total > 0;\n\nreturn [{\n  json: {\n    vendor: parsed.vendor || 'Unknown Vendor',\n    invoice_number: parsed.invoice_number || 'N/A',\n    invoice_date: parsed.invoice_date || new Date().toISOString().split('T')[0],\n    currency: parsed.currency || 'USD',\n    subtotal,\n    vat_amount: vat,\n    total_amount: total,\n    expected_total: expectedTotal,\n    math_diff: diff,\n    is_math_valid: isMathValid,\n    audit_status: isMathValid ? 'APPROVED' : 'NEEDS_HUMAN_APPROVAL',\n    processed_at: new Date().toISOString()\n  }\n}];"
      },
      "id": "inv-math-validation",
      "name": "Validate Total vs VAT Math",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [920, 300]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "cond-math-check",
              "leftValue": "={{ $json.is_math_valid }}",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "rightValue": ""
            }
          ],
          "combinator": "and"
        }
      },
      "id": "inv-if-math-valid",
      "name": "Is Math Valid?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1160, 300]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Invoices",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Date": "={{ $json.invoice_date }}",
            "Invoice No": "={{ $json.invoice_number }}",
            "Vendor": "={{ $json.vendor }}",
            "Currency": "={{ $json.currency }}",
            "Subtotal": "={{ $json.subtotal }}",
            "VAT": "={{ $json.vat_amount }}",
            "Total": "={{ $json.total_amount }}",
            "Status": "={{ $json.audit_status }}"
          }
        },
        "options": {}
      },
      "id": "inv-sheets-append",
      "name": "Google Sheets - Append Invoice Row",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [1400, 180],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "google-sheets-cred-placeholder",
          "name": "Google Sheets Account"
        }
      }
    },
    {
      "parameters": {
        "channel": "#finance-discrepancies",
        "text": "=⚠️ *Invoice Audit Mismatch*: {{ $json.vendor }} (#{{ $json.invoice_number }})\n*Subtotal + VAT*: {{ $json.expected_total }} {{ $json.currency }}\n*Parsed Total*: {{ $json.total_amount }} {{ $json.currency }}\n*Discrepancy*: {{ $json.math_diff }} {{ $json.currency }}\n*Action*: Routed to manual reconciliation queue.",
        "options": {}
      },
      "id": "inv-slack-escalate",
      "name": "Slack - Route to Human Review",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [1400, 420],
      "credentials": {
        "slackApi": {
          "id": "slack-cred-placeholder",
          "name": "Slack Bot Account"
        }
      }
    }
  ],
  "connections": {
    "IMAP Email - Inbound Invoices": {
      "main": [
        [
          {
            "node": "Extract PDF Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract PDF Text": {
      "main": [
        [
          {
            "node": "OpenAI - Extract Financial Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Extract Financial Fields": {
      "main": [
        [
          {
            "node": "Validate Total vs VAT Math",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Total vs VAT Math": {
      "main": [
        [
          {
            "node": "Is Math Valid?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Math Valid?": {
      "main": [
        [
          {
            "node": "Google Sheets - Append Invoice Row",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack - Route to Human Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
