{
  "name": "Vendor Invoice 3-Way Match with n8n (free workflow JSON)",
  "nodes": [
    {
      "id": "aaf16a4f-1e1e-4576-b909-0080a6f2fca7",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 1000,
        "content": "## Vendor invoice 3-way match with duplicate check\n\nA person submits one vendor invoice line through an n8n form. The workflow blocks the submission if the same Vendor ID and Invoice Number are already in the register. Otherwise it adds the invoice to the register as PENDING_MATCH, looks up the purchase order and the goods receipt in Google Sheets, compares them in code, and sets the status to READY_FOR_PAYMENT or PAYMENT_HOLD. Finance is told by email. Nothing is paid by this workflow.\n\n### How it works\n\n1. When Invoice Submitted: the form.\n2. Set Invoice Fields: trims and upper-cases the IDs and builds invoiceKey (VENDORID|INVOICENUMBER).\n3. Set Workflow Configurations: holds financeEmail.\n4. Read Invoice Register: looks for the same vendor and invoice number.\n5. If Duplicate Invoice: duplicate goes to Email Duplicate Invoice Warning; otherwise to Append Invoice to Register.\n6. Read Purchase Orders and Read Goods Receipts: take the first matching row.\n7. Execute 3-Way Match Logic: builds a list of exception reasons.\n8. Check 3-Way Match Outcome: no reasons means ready, otherwise hold.\n9. Update the status in the register and email Finance.\n\n### Setup\n\n1. Connect Google Sheets and Gmail credentials.\n2. Replace YOUR_GOOGLE_SHEET_ID in every Google Sheets node with your spreadsheet ID.\n3. Replace YOUR_FINANCE_EMAIL in Set Workflow Configurations.\n4. Create three tabs with these headers in row 1.\nInvoice Register: vendorId, vendorName, invoiceNumber, invoiceDate, poNumber, grnNumber, itemCode, invoiceQuantity, unitPrice, invoiceTotal, currency, submitterEmail, status, submittedAt, invoiceKey, exceptionReason.\nPurchase Orders: poNumber, itemCode, vendorId, currency, orderedQuantity, unitPrice, poStatus (APPROVED when approved).\nGoods Receipts: grnNumber, poNumber, itemCode, vendorId, receivedQuantity, receiptStatus (RECEIVED when received).\n5. Write IDs in the PO and receipt tabs in upper case, without spaces.\n6. Test with the form's test URL before publishing.\n\n### Customize\n\n- Tolerances, tax and extra rules: Execute 3-Way Match Logic.\n- Currencies: the dropdown in the form.\n- Email wording: the three Gmail nodes.\n\nSource: based on a template from the n8n Library at n8n.io, documented by LeenLabs.\nNot tested on live APIs."
      },
      "typeVersion": 1
    },
    {
      "id": "83e643a0-4b0c-4dd7-b2dc-454d73a7afef",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        16
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 320,
        "content": "## Capture invoice details\n\nReceives the invoice form submission, standardizes core invoice fields, and applies workflow-level settings such as the finance email address."
      },
      "typeVersion": 1
    },
    {
      "id": "d2b5434c-8ea4-4090-b283-d1ab362e81af",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1296,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 336,
        "content": "## Screen for duplicates\n\nLooks up the submitted invoice in Google Sheets, branches based on whether it already exists, and sends a duplicate invoice notification when needed."
      },
      "typeVersion": 1
    },
    {
      "id": "7b1087b5-076a-43dc-807f-fcb34b45fd10",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1888,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 736,
        "height": 304,
        "content": "## Register and retrieve records\n\nRecords the non-duplicate incoming invoice, then fetches the associated purchase order and goods receipt data needed for matching."
      },
      "typeVersion": 1
    },
    {
      "id": "7aaa0432-7474-4856-93e5-85d5d8c8941e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2688,
        432
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 320,
        "content": "## Evaluate 3-way match\n\nRuns the custom matching logic and branches according to whether the invoice, purchase order, and goods receipt agree."
      },
      "typeVersion": 1
    },
    {
      "id": "bdee05ee-cc02-400e-be0e-98a9a1081b05",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3152,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 320,
        "content": "## Approve payment path\n\nUpdates the invoice status to ready for payment and emails finance with the payment-ready notification."
      },
      "typeVersion": 1
    },
    {
      "id": "3cbcedad-926c-4d58-b76a-b0a6308af0d0",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3168,
        672
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 320,
        "content": "## Exception hold path\n\nUpdates the invoice as on hold when the match fails and sends finance an exception notification for follow-up."
      },
      "typeVersion": 1
    },
    {
      "id": "0e59c634-d944-42bd-8d8d-11639908f1a0",
      "name": "When Invoice Submitted",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        608,
        176
      ],
      "parameters": {
        "options": {},
        "formTitle": "Vendor Invoice Submission",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Vendor Name",
              "requiredField": true
            },
            {
              "fieldLabel": "Vendor ID",
              "requiredField": true
            },
            {
              "fieldLabel": "Invoice Number",
              "requiredField": true
            },
            {
              "fieldType": "date",
              "fieldLabel": "Invoice Date",
              "requiredField": true
            },
            {
              "fieldLabel": "PO Number",
              "requiredField": true
            },
            {
              "fieldLabel": "GRN Number",
              "requiredField": true
            },
            {
              "fieldLabel": "Item / SKU Code",
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Invoice Quantity",
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Unit Price",
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Invoice Total",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Currency",
              "fieldOptions": {
                "values": [
                  {
                    "option": "PKR"
                  },
                  {
                    "option": "USD"
                  },
                  {
                    "option": "EUR"
                  },
                  {
                    "option": "GBP"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "email",
              "fieldLabel": "Submitter Email",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Remarks"
            }
          ]
        },
        "formDescription": "Submit vendor invoice details for duplicate validation and PO-GRN-Invoice matching."
      },
      "typeVersion": 2.6
    },
    {
      "id": "b46860e1-30c4-4377-9f28-2164ee63891a",
      "name": "Set Invoice Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        832,
        176
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2986ac7b-f84a-49fd-86db-608c19bb11e1",
              "name": "vendorName",
              "type": "string",
              "value": "={{$json[\"Vendor Name\"]}}"
            },
            {
              "id": "f6b25ff7-67ce-45ec-ac1b-5eea63295b09",
              "name": "vendorId",
              "type": "string",
              "value": "={{$json[\"Vendor ID\"].trim().toUpperCase()}}"
            },
            {
              "id": "f751617a-f654-407a-a064-c08606f13690",
              "name": "invoiceNumber",
              "type": "string",
              "value": "={{$json[\"Invoice Number\"].trim().toUpperCase()}}"
            },
            {
              "id": "09947e66-a202-402c-81a0-68a34487943f",
              "name": "invoiceDate",
              "type": "string",
              "value": "={{$json[\"Invoice Date\"]}}"
            },
            {
              "id": "2b1fd86e-d969-4198-9bc8-20aca59ee057",
              "name": "poNumber",
              "type": "string",
              "value": "={{$json[\"PO Number\"].trim().toUpperCase()}}"
            },
            {
              "id": "e7ec44b2-06d9-4b0a-87d8-96b3447623da",
              "name": "grnNumber",
              "type": "string",
              "value": "={{$json[\"GRN Number\"].trim().toUpperCase()}}"
            },
            {
              "id": "e3d65106-2176-4dc0-bb75-d1330453a797",
              "name": "itemCode",
              "type": "string",
              "value": "={{$json[\"Item / SKU Code\"].trim().toUpperCase()}}"
            },
            {
              "id": "5fcdec6f-e3b6-4e1f-b744-a6943528e5e8",
              "name": "invoiceQuantity",
              "type": "number",
              "value": "={{$json[\"Invoice Quantity\"]}}"
            },
            {
              "id": "6a10b8e1-5540-456f-8fff-bc929cc44665",
              "name": "unitPrice",
              "type": "number",
              "value": "={{$json[\"Unit Price\"]}}"
            },
            {
              "id": "bbfbc877-9c62-4d35-8fce-1cd49719fa79",
              "name": "invoiceTotal",
              "type": "number",
              "value": "={{$json[\"Invoice Total\"]}}"
            },
            {
              "id": "23b6cbcd-e77a-40ea-95aa-9de0b64da45f",
              "name": "currency",
              "type": "string",
              "value": "={{$json[\"Currency\"]}}"
            },
            {
              "id": "fff31db5-edb5-4d77-bb94-7f2e813585c7",
              "name": "submitterEmail",
              "type": "string",
              "value": "={{$json[\"Submitter Email\"]}}"
            },
            {
              "id": "e118f252-d7c3-492e-8170-065accc33465",
              "name": "remarks",
              "type": "string",
              "value": "={{$json[\"Remarks\"]}}"
            },
            {
              "id": "da5c6e87-34d3-463a-8082-97ee391f6e0b",
              "name": "submittedAt",
              "type": "string",
              "value": "={{$json[\"submittedAt\"]}}"
            },
            {
              "id": "b3aa5db7-b62d-4aa0-89ab-d2f5facc8473",
              "name": "invoiceKey",
              "type": "string",
              "value": "={{$json[\"Vendor ID\"].trim().toUpperCase() + '|' + $json[\"Invoice Number\"].trim().toUpperCase()}}"
            }
          ]
        }
      },
      "typeVersion": 3.5
    },
    {
      "id": "59e8ed06-fa64-47c6-aae0-b95daf421f17",
      "name": "Read Invoice Register",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1344,
        176
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{$json.vendorId}}",
              "lookupColumn": "vendorId"
            },
            {
              "lookupValue": "={{$json.invoiceNumber}}",
              "lookupColumn": "invoiceNumber"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Invoice Register",
          "cachedResultName": "Invoice Register"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "4e9d279b-0230-45a9-a4c0-ecb1033a4deb",
      "name": "If Duplicate Invoice",
      "type": "n8n-nodes-base.if",
      "position": [
        1552,
        176
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "3dbbad48-c60e-44b0-8622-22f045cf9962",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{$json.invoiceNumber || ''}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "9200dfdd-bf38-4ec0-b60f-833bc11654a1",
      "name": "Append Invoice to Register",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1936,
        592
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "PENDING_MATCH",
            "currency": "={{ $('Set Invoice Fields').first().json.currency }}",
            "itemCode": "={{ $('Set Invoice Fields').first().json.itemCode }}",
            "poNumber": "={{ $('Set Invoice Fields').first().json.poNumber }}",
            "vendorId": "={{ $('Set Invoice Fields').first().json.vendorId }}",
            "grnNumber": "={{ $('Set Invoice Fields').first().json.grnNumber }}",
            "unitPrice": "={{ $('Set Invoice Fields').first().json.unitPrice }}",
            "invoiceKey": "={{ $('Set Invoice Fields').first().json.invoiceKey }}",
            "vendorName": "={{ $('Set Invoice Fields').first().json.vendorName }}",
            "invoiceDate": "={{ $('Set Invoice Fields').first().json.invoiceDate }}",
            "submittedAt": "={{ $('Set Invoice Fields').first().json.submittedAt }}",
            "invoiceTotal": "={{ $('Set Invoice Fields').first().json.invoiceTotal }}",
            "invoiceNumber": "={{ $('Set Invoice Fields').first().json.invoiceNumber }}",
            "submitterEmail": "={{ $('Set Invoice Fields').first().json.submitterEmail }}",
            "invoiceQuantity": "={{ $('Set Invoice Fields').first().json.invoiceQuantity }}"
          },
          "schema": [
            {
              "id": "vendorId",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "vendorId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "vendorName",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "vendorName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceNumber",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "invoiceNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceDate",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "invoiceDate",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "poNumber",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "poNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "grnNumber",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "grnNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "itemCode",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "itemCode",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceQuantity",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "invoiceQuantity",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "unitPrice",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "unitPrice",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceTotal",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "invoiceTotal",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "currency",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "submitterEmail",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "submitterEmail",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "submittedAt",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "submittedAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceKey",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "invoiceKey",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "exceptionReason",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "exceptionReason",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Invoice Register",
          "cachedResultName": "Invoice Register"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "2d335fd6-7548-4351-bdd7-27beac60e889",
      "name": "Read Purchase Orders",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2272,
        592
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{$json.poNumber}}",
              "lookupColumn": "poNumber"
            },
            {
              "lookupValue": "={{$json.itemCode}}",
              "lookupColumn": "itemCode"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Purchase Orders",
          "cachedResultName": "Purchase Orders"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "b83f800d-71ff-40d4-9626-2c6a03f53a88",
      "name": "Read Goods Receipts",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2480,
        592
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Set Invoice Fields').first().json.grnNumber }}",
              "lookupColumn": "grnNumber"
            },
            {
              "lookupValue": "={{ $('Set Invoice Fields').first().json.itemCode }}",
              "lookupColumn": "itemCode"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Goods Receipts",
          "cachedResultName": "Goods Receipts"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "29d7c904-e21f-4307-9ee2-2a3a0da0405c",
      "name": "Execute 3-Way Match Logic",
      "type": "n8n-nodes-base.code",
      "position": [
        2736,
        592
      ],
      "parameters": {
        "jsCode": "const invoice = $('Set Invoice Fields').first().json;\nconst po = $('Read Purchase Orders').first().json;\nconst grn = $('Read Goods Receipts').first().json;\n\nconst reasons = [];\n\nconst hasPO = Boolean(po && po.poNumber);\nconst hasGRN = Boolean(grn && grn.grnNumber);\n\nconst invoiceQty = Number(invoice.invoiceQuantity);\nconst invoiceUnitPrice = Number(invoice.unitPrice);\nconst invoiceTotal = Number(invoice.invoiceTotal);\n\nconst poQty = hasPO ? Number(po.orderedQuantity) : null;\nconst poUnitPrice = hasPO ? Number(po.unitPrice) : null;\nconst receivedQty = hasGRN ? Number(grn.receivedQuantity) : null;\n\nif (!hasPO) {\n  reasons.push('Purchase Order not found');\n} else {\n  if (po.poStatus !== 'APPROVED') {\n    reasons.push('Purchase Order is not approved');\n  }\n\n  if (invoice.vendorId !== po.vendorId) {\n    reasons.push('Vendor mismatch');\n  }\n\n  if (invoice.itemCode !== po.itemCode) {\n    reasons.push('Item / SKU mismatch');\n  }\n\n  if (invoice.poNumber !== po.poNumber) {\n    reasons.push('PO Number mismatch');\n  }\n\n  if (invoice.currency !== po.currency) {\n    reasons.push('Currency mismatch');\n  }\n\n  if (invoiceQty > poQty) {\n    reasons.push('Invoice quantity exceeds ordered quantity');\n  }\n\n  if (invoiceUnitPrice !== poUnitPrice) {\n    reasons.push('Unit price mismatch');\n  }\n}\n\nif (!hasGRN) {\n  reasons.push('Goods Receipt not found');\n} else {\n  if (grn.receiptStatus !== 'RECEIVED') {\n    reasons.push('Goods Receipt is not received');\n  }\n\n  if (invoice.vendorId !== grn.vendorId && !reasons.includes('Vendor mismatch')) {\n    reasons.push('Vendor mismatch');\n  }\n\n  if (invoice.itemCode !== grn.itemCode && !reasons.includes('Item / SKU mismatch')) {\n    reasons.push('Item / SKU mismatch');\n  }\n\n  if (invoice.poNumber !== grn.poNumber && !reasons.includes('PO Number mismatch')) {\n    reasons.push('PO Number mismatch');\n  }\n\n  if (invoice.grnNumber !== grn.grnNumber) {\n    reasons.push('GRN Number mismatch');\n  }\n\n  if (invoiceQty > receivedQty) {\n    reasons.push('Invoice quantity exceeds received quantity');\n  }\n}\n\nconst expectedTotal = hasPO && Number.isFinite(poUnitPrice)\n  ? invoiceQty * poUnitPrice\n  : null;\n\nif (\n  expectedTotal !== null &&\n  invoiceTotal !== expectedTotal\n) {\n  reasons.push('Invoice total mismatch');\n}\n\nreturn [\n  {\n    json: {\n      invoiceNumber: invoice.invoiceNumber,\n      vendorId: invoice.vendorId,\n      poNumber: invoice.poNumber,\n      grnNumber: invoice.grnNumber,\n      itemCode: invoice.itemCode,\n\n      invoiceQuantity: invoiceQty,\n      orderedQuantity: poQty,\n      receivedQuantity: receivedQty,\n\n      invoiceUnitPrice: invoiceUnitPrice,\n      poUnitPrice: poUnitPrice,\n\n      invoiceTotal: invoiceTotal,\n      expectedTotal: expectedTotal,\n\n      currency: invoice.currency,\n\n      matchPassed: reasons.length === 0,\n      matchStatus: reasons.length === 0 ? 'MATCHED' : 'MISMATCH',\n      exceptionReasons: reasons\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "7a2cd85b-aeab-4075-aad1-9381a2bf80c9",
      "name": "Check 3-Way Match Outcome",
      "type": "n8n-nodes-base.if",
      "position": [
        2960,
        592
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "af302e24-892d-467e-a126-af6d91dc3b70",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{$json.matchPassed}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "b05da145-04ad-408c-b8c1-630a1122dcec",
      "name": "Update Payment Ready Status",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3200,
        416
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "READY_FOR_PAYMENT",
            "invoiceKey": "={{$json.vendorId + '|' + $json.invoiceNumber}}"
          },
          "schema": [
            {
              "id": "vendorId",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "vendorId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "vendorName",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "vendorName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceNumber",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "invoiceNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceDate",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "invoiceDate",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "poNumber",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "poNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "grnNumber",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "grnNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "itemCode",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "itemCode",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceQuantity",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "invoiceQuantity",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "unitPrice",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "unitPrice",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceTotal",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "invoiceTotal",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "currency",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "submitterEmail",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "submitterEmail",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "submittedAt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "submittedAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceKey",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "invoiceKey",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "invoiceKey"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Invoice Register",
          "cachedResultName": "Invoice Register"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "2cecf2e9-6e59-44e6-9edc-d7f76f820f79",
      "name": "Email Finance: Payment Ready",
      "type": "n8n-nodes-base.gmail",
      "position": [
        3424,
        416
      ],
      "parameters": {
        "sendTo": "={{ $('Set Workflow Configurations').first().json.financeEmail }}",
        "message": "=Invoice has successfully passed 3-way matching and is ready for payment.  Invoice Number: {{$('Execute 3-Way Match Logic').first().json.invoiceNumber}} Vendor ID: {{$('Execute 3-Way Match Logic').first().json.vendorId}} PO Number: {{$('Execute 3-Way Match Logic').first().json.poNumber}} GRN Number: {{$('Execute 3-Way Match Logic').first().json.grnNumber}} Item Code: {{$('Execute 3-Way Match Logic').first().json.itemCode}}  Invoice Quantity: {{$('Execute 3-Way Match Logic').first().json.invoiceQuantity}} Received Quantity: {{$('Execute 3-Way Match Logic').first().json.receivedQuantity}}  Invoice Total: {{$('Execute 3-Way Match Logic').first().json.invoiceTotal}} Currency: {{$('Execute 3-Way Match Logic').first().json.currency}}  Status: READY_FOR_PAYMENT  This invoice passed PO, GRN, vendor, quantity, price and amount validation.",
        "options": {},
        "subject": "=Invoice Ready for Payment - {{$json.invoiceKey}}",
        "emailType": "text"
      },
      "typeVersion": 2.2
    },
    {
      "id": "f50ba3b3-e395-4c8a-932a-b10f8f7ec39b",
      "name": "Update Payment Hold Status",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3216,
        832
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "PAYMENT_HOLD",
            "invoiceKey": "={{$json.vendorId + '|' + $json.invoiceNumber}}",
            "exceptionReason": "={{$json.exceptionReasons.join(', ')}}"
          },
          "schema": [
            {
              "id": "vendorId",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "vendorId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "vendorName",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "vendorName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceNumber",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "invoiceNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceDate",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "invoiceDate",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "poNumber",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "poNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "grnNumber",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "grnNumber",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "itemCode",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "itemCode",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceQuantity",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "invoiceQuantity",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "unitPrice",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "unitPrice",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceTotal",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "invoiceTotal",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "currency",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "currency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "submitterEmail",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "submitterEmail",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "submittedAt",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "submittedAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "invoiceKey",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "invoiceKey",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "exceptionReason",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "exceptionReason",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "invoiceKey"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Invoice Register",
          "cachedResultName": "Invoice Register"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "a7af683a-af9a-4e1b-869e-16b147f49eaf",
      "name": "Email Finance: On Hold",
      "type": "n8n-nodes-base.gmail",
      "position": [
        3424,
        832
      ],
      "parameters": {
        "sendTo": "={{ $('Set Workflow Configurations').first().json.financeEmail }}",
        "message": "=Invoice failed 3-way matching and has been placed on payment hold.  Invoice Number: {{$('Execute 3-Way Match Logic').first().json.invoiceNumber}} Vendor ID: {{$('Execute 3-Way Match Logic').first().json.vendorId}} PO Number: {{$('Execute 3-Way Match Logic').first().json.poNumber}} GRN Number: {{$('Execute 3-Way Match Logic').first().json.grnNumber}} Item Code: {{$('Execute 3-Way Match Logic').first().json.itemCode}}  Exception Reason: {{$('Execute 3-Way Match Logic').first().json.exceptionReasons.join(', ')}}  Invoice Total: {{$('Execute 3-Way Match Logic').first().json.invoiceTotal}} Expected Total: {{$('Execute 3-Way Match Logic').first().json.expectedTotal}} Currency: {{$('Execute 3-Way Match Logic').first().json.currency}}  Status: PAYMENT_HOLD",
        "options": {},
        "subject": "=Invoice Payment Hold - {{$json.invoiceKey}}",
        "emailType": "text"
      },
      "typeVersion": 2.2
    },
    {
      "id": "44531524-039f-4c65-9232-910f932821fc",
      "name": "Email Duplicate Invoice Warning",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1792,
        160
      ],
      "parameters": {
        "sendTo": "={{ $('Set Invoice Fields').first().json.submitterEmail }}",
        "message": "=A duplicate vendor invoice submission has been detected and blocked.\n\nVendor: {{ $('Set Invoice Fields').first().json.vendorName }}\nVendor ID: {{ $('Set Invoice Fields').first().json.vendorId }}\nInvoice Number: {{ $('Set Invoice Fields').first().json.invoiceNumber }}\nPO Number: {{ $('Set Invoice Fields').first().json.poNumber }}\n\nReason:\nThe same Vendor ID and Invoice Number already exist in the Invoice Register.\n\nAction:\nNo new invoice record was created and no payment processing was initiated.\n\nStatus: DUPLICATE_BLOCKED",
        "options": {},
        "subject": "=Duplicate Invoice Blocked - {{ $('Set Invoice Fields').first().json.invoiceNumber }}",
        "emailType": "text"
      },
      "typeVersion": 2.2
    },
    {
      "id": "2ddf1a37-16ef-4eec-b5d5-c8f730bb7c40",
      "name": "Set Workflow Configurations",
      "type": "n8n-nodes-base.set",
      "position": [
        1040,
        176
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "07cf1d0c-b1df-4aee-bba5-1275bfedec4d",
              "name": "financeEmail",
              "type": "string",
              "value": "YOUR_FINANCE_EMAIL"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.5
    },
    {
      "id": "7c3e9a41-5b28-4d6f-a1e0-92b4d8f60c35",
      "name": "Before you turn it on",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -1040
      ],
      "parameters": {
        "color": 3,
        "width": 480,
        "height": 960,
        "content": "## Before you turn it on\n\n1. The match compares what the submitter typed in the form with your PO and receipt sheets. It never sees the real invoice document. Someone who types matching numbers gets READY_FOR_PAYMENT. Check the real invoice before paying.\n2. The form is one invoice line per submission. A second line of the same invoice is blocked as a duplicate.\n3. The invoice total must equal quantity times PO unit price exactly. Tax, shipping and discounts make it fail, and decimals can cause false mismatches.\n4. If the ordered or received quantity column is missing or not a number, the quantity check against that sheet is skipped without any message. Zero and negative quantities also pass.\n5. Only the first matching PO row and receipt row are used. Partial deliveries, several PO lines and earlier invoices on the same PO are not added up.\n6. The row is added as PENDING_MATCH before matching. If a later step fails, the row stays pending and the same invoice number is then blocked as a duplicate.\n7. A held invoice also blocks a corrected resubmission with the same invoice number until you fix or delete the row.\n8. Anyone with the form link can submit, and the workflow emails the address typed in the form. Restrict access.\n9. The Remarks field is collected but never stored or sent.\n10. Use the test URL with fake data first. Production runs write to your real register."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Set Invoice Fields": {
      "main": [
        [
          {
            "node": "Set Workflow Configurations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Goods Receipts": {
      "main": [
        [
          {
            "node": "Execute 3-Way Match Logic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Duplicate Invoice": {
      "main": [
        [
          {
            "node": "Email Duplicate Invoice Warning",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Append Invoice to Register",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Purchase Orders": {
      "main": [
        [
          {
            "node": "Read Goods Receipts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Invoice Register": {
      "main": [
        [
          {
            "node": "If Duplicate Invoice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Invoice Submitted": {
      "main": [
        [
          {
            "node": "Set Invoice Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check 3-Way Match Outcome": {
      "main": [
        [
          {
            "node": "Update Payment Ready Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update Payment Hold Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute 3-Way Match Logic": {
      "main": [
        [
          {
            "node": "Check 3-Way Match Outcome",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Invoice to Register": {
      "main": [
        [
          {
            "node": "Read Purchase Orders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Payment Hold Status": {
      "main": [
        [
          {
            "node": "Email Finance: On Hold",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Workflow Configurations": {
      "main": [
        [
          {
            "node": "Read Invoice Register",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Payment Ready Status": {
      "main": [
        [
          {
            "node": "Email Finance: Payment Ready",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  }
}