{
  "id": "tQ9I6eL2AXQ6zTTQ",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Invoice Instructor",
  "tags": [],
  "nodes": [
    {
      "id": "f22ac2f5-17c1-40f1-8745-302f18b03ffb",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -528,
        -96
      ],
      "parameters": {
        "options": {
          "allowFileUploads": true
        }
      },
      "typeVersion": 1.4
    },
    {
      "id": "246b6eda-e99f-4206-b512-aeac09444958",
      "name": "Analyze document",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        -144,
        16
      ],
      "parameters": {
        "text": "Return a clean JSON object containing the invoice main details and an array of all line items. Format exactly like this:\n{\n  \"vendor\": \"Name\",\n  \"invoice_number\": \"123\",\n  \"date\": \"YYYY-MM-DD\",\n  \"total_amount\": 1000.00,\n  \"items\": [\n    {\"description\": \"Item 1\", \"qty\": 1, \"price\": 100, \"line_total\": 100}\n  ]\n}\nDo not wrap inside markdown code blocks. Keep names brief.",
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-flash-lite-latest",
          "cachedResultName": "models/gemini-flash-lite-latest"
        },
        "options": {
          "maxOutputTokens": 3000
        },
        "resource": "document",
        "inputType": "binary",
        "binaryPropertyName": "data0"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3a3e6097-43af-4a18-8bdb-dac88a0d2b77",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        192,
        -80
      ],
      "parameters": {
        "jsCode": "// 1. Gemini ka raw text response parse karein\nconst rawText = $input.item.json.content.parts[0].text;\nconst invoiceData = JSON.parse(rawText);\n\n// 2. Line items ke liye HTML rows generate karein\nlet itemRows = '';\ninvoiceData.items.forEach(item => {\n    itemRows += `\n        <tr style=\"border-bottom: 1px solid #dddddd;\">\n            <td style=\"padding: 12px; font-size: 14px; color: #333333;\">${item.description}</td>\n            <td style=\"padding: 12px; text-align: center; font-size: 14px; color: #333333;\">${item.qty}</td>\n            <td style=\"padding: 12px; text-align: right; font-size: 14px; color: #333333;\">${Number(item.price).toFixed(2)}</td>\n            <td style=\"padding: 12px; text-align: right; font-size: 14px; font-weight: bold; color: #333333;\">${Number(item.line_total).toFixed(2)}</td>\n        </tr>\n    `;\n});\n\n// 3. Poora Sundar HTML Template taiyar karein\nconst htmlTemplate = `\n<div style=\"font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 600px; margin: auto; border: 1px solid #e0e0e0; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); overflow: hidden;\">\n    <!-- Header -->\n    <div style=\"background: linear-gradient(135deg, #4F46E5, #3730A3); color: #ffffff; padding: 24px; text-align: center;\">\n        <h2 style=\"margin: 0; font-size: 24px; font-weight: 600; letter-spacing: 0.5px;\">Invoice Processed Successfully</h2>\n        <p style=\"margin: 5px 0 0 0; opacity: 0.9; font-size: 14px;\">Automated Data Extraction Log</p>\n    </div>\n\n    <!-- Main Details Box -->\n    <div style=\"padding: 24px; background-color: #f9fafb;\">\n        <table style=\"width: 100%; border-collapse: collapse; font-size: 14px;\">\n            <tr>\n                <td style=\"padding: 6px 0; color: #6b7280;\"><b>Vendor Name:</b></td>\n                <td style=\"padding: 6px 0; text-align: right; color: #111827; font-weight: 600;\">${invoiceData.vendor}</td>\n            </tr>\n            <tr>\n                <td style=\"padding: 6px 0; color: #6b7280;\"><b>Invoice Number:</b></td>\n                <td style=\"padding: 6px 0; text-align: right; color: #111827;\">#${invoiceData.invoice_number}</td>\n            </tr>\n            <tr>\n                <td style=\"padding: 6px 0; color: #6b7280;\"><b>Invoice Date:</b></td>\n                <td style=\"padding: 6px 0; text-align: right; color: #111827;\">${invoiceData.date}</td>\n            </tr>\n        </table>\n    </div>\n\n    <!-- Line Items Table -->\n    <div style=\"padding: 20px 24px;\">\n        <h4 style=\"margin: 0 0 12px 0; color: #374151; font-size: 16px; border-bottom: 2px solid #F3F4F6; padding-bottom: 6px;\">Itemized Breakdown</h4>\n        <table style=\"width: 100%; border-collapse: collapse;\">\n            <thead>\n                <tr style=\"background-color: #F9FAFB; border-bottom: 2px solid #E5E7EB;\">\n                    <th style=\"text-align: left; padding: 10px; font-size: 12px; text-transform: uppercase; color: #4B5563;\">Description</th>\n                    <th style=\"text-align: center; padding: 10px; font-size: 12px; text-transform: uppercase; color: #4B5563;\">Qty</th>\n                    <th style=\"text-align: right; padding: 10px; font-size: 12px; text-transform: uppercase; color: #4B5563;\">Price</th>\n                    <th style=\"text-align: right; padding: 10px; font-size: 12px; text-transform: uppercase; color: #4B5563;\">Total</th>\n                </tr>\n            </thead>\n            <tbody>\n                ${itemRows}\n            </tbody>\n        </table>\n    </div>\n\n    <!-- Grand Total Box -->\n    <div style=\"padding: 16px 24px; background-color: #EEF2F6; display: flex; justify-content: space-between; align-items: center; border-top: 1px solid #E2E8F0;\">\n        <span style=\"font-size: 16px; font-weight: bold; color: #1E293B;\">Grand Total:</span>\n        <span style=\"font-size: 20px; font-weight: 800; color: #4F46E5; text-align: right; display: block; width: 100%;\">\n            $${Number(invoiceData.total_amount).toFixed(2)}\n        </span>\n    </div>\n\n    <!-- Footer -->\n    <div style=\"background-color: #f3f4f6; padding: 12px; text-align: center; font-size: 11px; color: #9ca3af; border-top: 1px solid #e5e7eb;\">\n        This is an automated system confirmation. Data logged into Google Sheets.\n    </div>\n</div>\n`;\n\n// 4. Agle nodes ke liye data pack karke bheinjein\n// Hum Sheets ke liye array format bhi de rahe hain aur email ke liye poora HTML block bhi\nreturn invoiceData.items.map(item => {\n    return {\n        vendor: invoiceData.vendor,\n        invoice_number: invoiceData.invoice_number,\n        date: invoiceData.date,\n        total_amount: invoiceData.total_amount,\n        item_description: item.description,\n        item_qty: item.qty,\n        item_price: item.price,\n        item_total: item.line_total,\n        email_body: htmlTemplate // Ye variable seedha Gmail node me use hoga\n    };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "36695aae-6ccc-4e8a-917b-ce0ef6fe0c46",
      "name": "Append row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1424,
        -112
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.date }}",
            "Price": "={{ $json.item_price }}",
            "Vendor": "={{ $json.vendor }}",
            "Quantity": "={{ $json.item_qty }}",
            "Line Total": "={{ $json.item_total }}",
            "Total Amount": "={{ $json.total_amount }}",
            "Invoice Number": "={{ $json.invoice_number }}",
            "Item Description": "={{ $json.item_description }}"
          },
          "schema": [
            {
              "id": "Vendor",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Vendor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Amount",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Total Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Item Description",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Item Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Quantity",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Quantity",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Price",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Price",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Line Total",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Line Total",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "cellFormat": "USER_ENTERED"
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/16VaehtglNZ6bhgq4m8NvormwPoJrcg-LF3fWj3P0xiY/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "16VaehtglNZ6bhgq4m8NvormwPoJrcg-LF3fWj3P0xiY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/16VaehtglNZ6bhgq4m8NvormwPoJrcg-LF3fWj3P0xiY/edit?usp=drivesdk",
          "cachedResultName": "Invoice sheet "
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "a983ef2e-adc4-4708-b6af-a384b2c7e087",
      "name": "Send a message",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2016,
        -112
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "={{ $('Code in JavaScript1').first().json.email_body }}",
        "options": {},
        "subject": "={{ $('Code in JavaScript1').first().json.vendor }} - New Invoice Processed"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "89bf31de-6a44-42ca-bd8a-f661fc4dac46",
      "name": "Get row(s) in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        528,
        -80
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KBcqJu-x7-bOoMzPjXjJchktrdOPjas5-LVDgC0L8MA/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1KBcqJu-x7-bOoMzPjXjJchktrdOPjas5-LVDgC0L8MA",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KBcqJu-x7-bOoMzPjXjJchktrdOPjas5-LVDgC0L8MA/edit?usp=drivesdk",
          "cachedResultName": "Invoice Sheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "7a85f7fb-3012-4b22-9c37-78fbf418fa21",
      "name": "Code in JavaScript1",
      "type": "n8n-nodes-base.code",
      "position": [
        832,
        -80
      ],
      "parameters": {
        "jsCode": "// 1. Puraane Code node se naye invoice ke saare items nikalein\nconst newInvoices = $('Code in JavaScript').all(); \n\n// 2. Google Sheets se saare existing rows nikalein\nconst existingRows = $('Get row(s) in sheet').all(); \n\nlet validatedItems = [];\n\n// Saare naye items par ek-ek karke check chalayenge\nfor (const item of newInvoices) {\n    const invoiceData = item.json;\n\n    // --- CHECK 1: MISSING DATA CHECK ---\n    if (!invoiceData.invoice_number || !invoiceData.vendor || !invoiceData.total_amount) {\n        validatedItems.push({\n            json: {\n                status: \"FAIL\",\n                reason: \"Missing critical fields (Invoice Number, Vendor, or Total Amount)\",\n                ...invoiceData\n            }\n        });\n        continue;\n    }\n\n    // --- CHECK 2: DUPLICATE CHECK ---\n    const isDuplicate = existingRows.some(row => String(row.json['Invoice Number']) === String(invoiceData.invoice_number));\n\n    if (isDuplicate) {\n        validatedItems.push({\n            json: {\n                status: \"FAIL\",\n                reason: `Duplicate Invoice Detected! Invoice #${invoiceData.invoice_number} already exists.`,\n                ...invoiceData\n            }\n        });\n    } else {\n        // Agar dono check PASS ho gaye\n        validatedItems.push({\n            json: {\n                status: \"PASS\",\n                ...invoiceData\n            }\n        });\n    }\n}\n\nreturn validatedItems;"
      },
      "typeVersion": 2
    },
    {
      "id": "ac34c731-660f-48f5-b605-3874a091ee38",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        1120,
        -80
      ],
      "parameters": {
        "options": {
          "ignoreCase": false
        },
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1575ddb4-920a-476e-b175-80ac1a1e895a",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "PASS"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "ecfdeae6-4d44-4943-a6ff-f9c849c790c8",
      "name": "Summarize",
      "type": "n8n-nodes-base.summarize",
      "position": [
        1712,
        -96
      ],
      "parameters": {
        "options": {},
        "fieldsToSummarize": {
          "values": [
            {
              "field": "Vendor",
              "aggregation": "append"
            },
            {}
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "a6df1d20-8002-409a-b8f5-7623b80726f0",
      "name": "Format Duplicate Alert",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1264,
        400
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "=<div style=\"font-family: Arial, sans-serif; max-width: 600px; border: 1px solid #ff4d4d; border-radius: 8px; padding: 20px; background-color: #fff5f5;\">\n  <h2 style=\"color: #cc0000; margin-top: 0;\">\u26a0\ufe0f Duplicate Invoice Detected</h2>\n  <p>The following invoice already exists in the Google Sheets log, so it was <strong>skipped</strong> to prevent duplicate records:</p>\n  \n  <table style=\"width: 100%; border-collapse: collapse; margin-top: 15px;\">\n    <tr style=\"background-color: #ffe6e6;\">\n      <th style=\"padding: 10px; border: 1px solid #ffcccc; text-align: left;\">Field</th>\n      <th style=\"padding: 10px; border: 1px solid #ffcccc; text-align: left;\">Value</th>\n    </tr>\n    <tr>\n      <td style=\"padding: 10px; border: 1px solid #ffcccc; font-weight: bold;\">Invoice Number</td>\n      <td style=\"padding: 10px; border: 1px solid #ffcccc;\">{{ $json.invoiceNumber }}</td>\n    </tr>\n    <tr>\n      <td style=\"padding: 10px; border: 1px solid #ffcccc; font-weight: bold;\">Vendor</td>\n      <td style=\"padding: 10px; border: 1px solid #ffcccc;\">{{ $json.vendor }}</td>\n    </tr>\n    <tr>\n      <td style=\"padding: 10px; border: 1px solid #ffcccc; font-weight: bold;\">Total Amount</td>\n      <td style=\"padding: 10px; border: 1px solid #ffcccc;\">{{ $json.totalAmount }}</td>\n    </tr>\n  </table>\n  \n  <p style=\"margin-top: 20px; font-size: 12px; color: #777;\">This is an automated operational alert from your n8n Invoice Validation Workflow.</p>\n</div>",
        "options": {},
        "subject": "=\u26a0\ufe0f Alert: Duplicate Invoice Skipped - {{ $json.invoiceNumber }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "fc615c20-eb20-4533-80a0-c1151c11ce9c",
      "name": "Code in JavaScript2",
      "type": "n8n-nodes-base.code",
      "position": [
        784,
        400
      ],
      "parameters": {
        "jsCode": "// Is node mein hum duplicate invoice ka data format kar rahe hain\nreturn [\n  {\n    json: {\n      invoiceNumber: $('Code in JavaScript1').item.json.invoiceNumber || \"N/A\",\n      vendor: $('Code in JavaScript1').item.json.vendor || \"Unknown\",\n      totalAmount: $('Code in JavaScript1').item.json.totalAmount || \"0.00\"\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "c3d2c049-aa51-4ee0-aa4d-cf991ccba1e6",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        -432
      ],
      "parameters": {
        "color": "#FFF9C4",
        "width": 304,
        "height": 432,
        "content": "### Node 1: When chat message received\n\nThis is a **trigger node** that kicks off the entire processing automation whenever a new document is sent to the chat.\n\n* **Binary Capture:** Automatically grabs files (PDFs/Images) uploaded by the user.\n* **Instant Start:** Initiates downstream execution instantly on message arrival."
      },
      "typeVersion": 1
    },
    {
      "id": "01c4ed30-06d1-42c4-81f5-4dcb81259228",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        -320
      ],
      "parameters": {
        "color": "#FFE0E0",
        "width": 288,
        "height": 432,
        "content": "### Node 2: Analyze document\n\nThis node uses **Google Gemini** as the analytical reasoning engine to read the visual data inside the invoice.\n\n* **Information Extraction:** Extracts key fields like Vendor Name, Invoice Number, Date, and Line Items.\n* **Structured Output:** Converts raw visual document details directly into a readable data format."
      },
      "typeVersion": 1
    },
    {
      "id": "04d041f8-8ccc-4d8a-a8b3-46f4c6994a65",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        96,
        -384
      ],
      "parameters": {
        "color": "#E0F2FF",
        "width": 304,
        "height": 400,
        "content": "### Node 3: Code in JavaScript\n\nThis node acts as a cleaning layer to structure raw output before database storage.\n\n* **Formatting:** Restructures the extracted keys into consistent JSON naming conventions.\n* **Safety:** Prepares cleanly structured objects to avoid errors in subsequent steps."
      },
      "typeVersion": 1
    },
    {
      "id": "99800640-d6c6-4cd1-8c3e-201c1bc6ccc0",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        432,
        -384
      ],
      "parameters": {
        "color": "#E0F2E0",
        "width": 288,
        "height": 400,
        "content": "### Node 4: Read Database Sheet\n\nThis node connects to the target Google Sheet to fetch existing logged invoices.\n\n* **Data Retrieval:** Pulls previously saved invoice numbers for real-time comparison.\n* **Safety Check:** Essential step to verify the current file is not a duplicate."
      },
      "typeVersion": 1
    },
    {
      "id": "b06216ae-3bab-48dc-b93e-259859515a0b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        -384
      ],
      "parameters": {
        "color": "#E0F2FF",
        "width": 288,
        "height": 400,
        "content": "### Node 5: Duplicate Logic Check\n\nThis processing node compares the incoming invoice details with historical spreadsheet entries.\n\n* **Value Matching:** Scans fetched list to check if current Invoice ID/Number already exists.\n* **Flag Setting:** Flags the transaction as Unique (True) or Duplicate (False)."
      },
      "typeVersion": 1
    },
    {
      "id": "58c730d4-c847-415d-99b8-b689832674fe",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1040,
        -384
      ],
      "parameters": {
        "color": "#F3E5F5",
        "width": 288,
        "height": 400,
        "content": "### Node 6: Routing Decision (If)\n\nA structural branch node that directs the rest of the execution flow based on validation.\n\n* **True Branch (Upper):** Unique invoice. Routes to logging and success notification.\n* **False Branch (Lower):** Duplicate invoice. Routes directly to error logging and email warnings."
      },
      "typeVersion": 1
    },
    {
      "id": "d1a10900-8b3e-4865-aac6-ba54350b59d7",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        -400
      ],
      "parameters": {
        "color": "#E0F2E0",
        "width": 272,
        "height": 384,
        "content": "### Node 7: Log Unique Invoice\n\nThis node writes the verified data parameters directly into the Google Sheet.\n\n* **Database Entry:** Appends Vendor, Invoice Number, Date, and Amount.\n* **Permanent Record:** Keeps your active financial log cleanly updated."
      },
      "typeVersion": 1
    },
    {
      "id": "51a146b7-73e7-4256-93c5-94000204e530",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1632,
        -400
      ],
      "parameters": {
        "color": "#E0F2FF",
        "width": 272,
        "height": 400,
        "content": "### Node 8: Generate Summary\n\nThis node packages the newly logged dataset elements together.\n\n* **Payload Preparation:** Organizes key values into a clean HTML/text format.\n* **Mail Readiness:** Constructs the core details needed for the success email template."
      },
      "typeVersion": 1
    },
    {
      "id": "32315be0-c5ce-4dae-8506-2f9263006eca",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1920,
        -416
      ],
      "parameters": {
        "color": "#FFE0E0",
        "width": 288,
        "height": 400,
        "content": "### Node 9: Send Success Mail\n\nDispatches an immediate message notifying the team about the newly archived document.\n\n* **User Confirmation:** Delivers a clean HTML table summarizing the processed invoice fields.\n* **Completes Flow:** Ends the standard success execution loop."
      },
      "typeVersion": 1
    },
    {
      "id": "d8b53807-c36c-493e-a515-8369efb14008",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        128
      ],
      "parameters": {
        "color": "#342342",
        "width": 352,
        "height": 416,
        "content": "### Node 10: Format Duplicate Warning\n\nConstructs an error alert details object when a duplicate file match is found.\n\n* **Incident Packaging:** Pairs the current file data with the conflicting database invoice number.\n* **Alert Text:** Builds a clear alert message for prompt review."
      },
      "typeVersion": 1
    },
    {
      "id": "4db330f0-5fdd-4861-919a-5cbf172dff7e",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1136,
        128
      ],
      "parameters": {
        "color": "#F494A7",
        "width": 352,
        "height": 432,
        "content": "Node 11: Trigger Warning Email\n\nSends an instant notice flagging that a duplicate processing attempt was successfully intercepted.\n\n* **Database Protection:** Alerts administrators to prevent multiple billing entries.\n* **Security Reporting:** Provides full transparency on blocked actions."
      },
      "typeVersion": 1
    },
    {
      "id": "2306d6c9-4186-4e7a-9ef2-facde6d9f00b",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1280,
        -496
      ],
      "parameters": {
        "color": "#DED6B8",
        "width": 464,
        "height": 1088,
        "content": "**[Invoice Instructor] Automated Document Pipeline**\n\nThis production-grade n8n template automates the ingestion, structural analysis, and database validation of business invoices in real-time.\n\n---\n\n### **How It Works**\n* **Trigger:** Initiated automatically when a chat interface receives an uploaded invoice file (PDF or Image).\n* **AI Analysis:** Google Gemini extracts core invoice parameters (Vendor, Invoice ID, Date, Amount) into structured JSON.\n* **Cleaning Layer:** Custom JavaScript standardizes data formats to prevent storage errors.\n* **Database Check:** Queries the master Google Sheet to cross-reference historical logs.\n* **Smart Routing:** Splits the path\u2014uniques are written to the database with a success email, while duplicates are instantly blocked and reported via duplicate alerts.\n\n---\n\n### **How To Use**\n1. Ensure your Gemini API credentials and Google Sheets integrations are fully authenticated.\n2. Upload any invoice file directly into the designated chat window.\n3. If an invoice is successfully processed, check your Google Sheets and inbox for the formatted summary email.\n4. If a file is blocked, review the \"Format Duplicate Alert\" notification details.\n\n---\n\n### **Requirements**\n* Google Gemini API Key\n* Master Google Sheets database\n* Gmail connection for alerts and summaries\n\n---\n\n### **Need Help?**\nFor workflow customizations, schema updates, or deployment support, please contact the Internal Automation & Development Team."
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "de5b4041-73e4-4b89-895b-29a99ec2f09f",
  "nodeGroups": [],
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Append row in sheet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Code in JavaScript2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarize": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze document": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append row in sheet": {
      "main": [
        [
          {
            "node": "Summarize",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript2": {
      "main": [
        [
          {
            "node": "Format Duplicate Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Analyze document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}