{
  "name": "[Demo] Belegverarbeitung Treuhand",
  "description": null,
  "nodes": [
    {
      "id": "YOUR_DRIVE_FOLDER_ID",
      "name": "\ud83d\udce7 Email Eingang",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        280,
        304
      ],
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "parameters": {
        "operation": "getAll",
        "returnAll": false,
        "limit": 20,
        "filters": {
          "q": "has:attachment filename:pdf is:unread"
        },
        "options": {
          "downloadAttachments": true
        }
      }
    },
    {
      "parameters": {
        "operation": "pdf",
        "binaryPropertyName": "attachment_0",
        "options": {}
      },
      "id": "pdf-extract-01",
      "name": "\ud83d\udcc4 PDF Text extrahieren",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        720,
        304
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "anthropicApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.apiBody }}",
        "options": {}
      },
      "id": "ai-class-01",
      "name": "\ud83e\udd16 AI Klassifikation",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1320,
        304
      ],
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "maxTries": 5,
      "waitBetweenTries": 3000
    },
    {
      "parameters": {
        "jsCode": "const allItems = $input.all();\nconst pdfItems = $('\ud83d\udcc4 PDF Text extrahieren').all();\nconst attachItems = $('\ud83d\udce5 Attachment laden').all();\nconst uploadItems = $('\ud83d\udce4 In Unverarbeitet ablegen').all();\n\nconst mandanten = [\n  {name:'Beispiel A AG', aliases:['Beispiel A AG','Beispiel A','Musterstrasse 1','Beispiel-A'],\n   ordner:'Beispiel A', sb:'Max Muster', email:'your-email@example.com',\n   folders:{Rechnungen:'YOUR_DRIVE_FOLDER_ID',Lohnabrechnungen:'YOUR_DRIVE_FOLDER_ID',Quittungen:'YOUR_DRIVE_FOLDER_ID'}},\n  {name:'Beispiel A', aliases:['Beispiel A','Musterstrasse 1','Beispiel-B'],\n   ordner:'Beispiel A', sb:'Max Muster', email:'your-email@example.com',\n   folders:{Rechnungen:'YOUR_DRIVE_FOLDER_ID',Lohnabrechnungen:'YOUR_DRIVE_FOLDER_ID',Quittungen:'YOUR_DRIVE_FOLDER_ID'}},\n  {name:'M\\u00fcller AG', aliases:['Beispiel A','M\\u00fcller AG','Muller AG','Musterstrasse 1'],\n   ordner:'Beispiel A', sb:'Max Muster', email:'your-email@example.com',\n   folders:{Rechnungen:'YOUR_DRIVE_FOLDER_ID',Lohnabrechnungen:'YOUR_DRIVE_FOLDER_ID',Quittungen:'YOUR_DRIVE_FOLDER_ID'}}\n];\n\nconst UNZUGEORDNET_ID = 'YOUR_DRIVE_FOLDER_ID';\nconst typMap = {rechnung:'Rechnungen',lohnabrechnung:'Lohnabrechnungen',quittung:'Quittungen',spesenabrechnung:'Quittungen',steuerabrechnung:'Rechnungen',versicherung:'Rechnungen'};\n\nconst results = [];\n\nfor (let i = 0; i < allItems.length; i++) {\n  try {\n    const content = allItems[i].json.content[0].text;\n    let jsonStr = content.trim();\n    // Strip markdown code fences AND bare \"json\" prefix\n    if (jsonStr.includes('```')) jsonStr = jsonStr.replace(/```json?\\n?/g,'').replace(/```/g,'').trim();\n    if (jsonStr.startsWith('json')) jsonStr = jsonStr.replace(/^json\\s*/, '').trim();\n    const ai = JSON.parse(jsonStr);\n\n    const pdfText = (pdfItems[i] && pdfItems[i].json.text) || '';\n    const emailSubject = (attachItems[i] && attachItems[i].json.subject) || '';\n    const driveFileId = (uploadItems[i] && uploadItems[i].json.id) || '';\n\n    const searchText = [ai.empfaenger||'',ai.absender||'',ai.zusammenfassung||'',pdfText,emailSubject].join(' ').toLowerCase();\n\n    let m = null;\n    for (const x of mandanten) {\n      for (const a of x.aliases) {\n        if (searchText.includes(a.toLowerCase())) { m = x; break; }\n      }\n      if (m) break;\n    }\n\n    const unterordner = typMap[ai.dokumenttyp] || 'Rechnungen';\n    const zielordner_id = m ? (m.folders[unterordner] || m.folders['Rechnungen']) : UNZUGEORDNET_ID;\n    const datum = (ai.datum||'').replace(/-/g,'');\n    const absender = (ai.absender||'Unbekannt').replace(/[^a-zA-Z\\u00e4\\u00f6\\u00fc\\u00c4\\u00d6\\u00dc0-9]/g,'_');\n\n    results.push({json:{\n      dokumenttyp:ai.dokumenttyp, absender:ai.absender, empfaenger:ai.empfaenger,\n      betrag:ai.betrag, datum:ai.datum, faellig_bis:ai.faellig_bis,\n      referenz:ai.referenz, zusammenfassung:ai.zusammenfassung, konfidenz:ai.konfidenz,\n      mandant_name: m?m.name:'UNBEKANNT',\n      sachbearbeiter: m?m.sb:'Unbekannt',\n      sachbearbeiter_email: m?m.email:'your-email@example.com',\n      zielordner: m?'Mandanten/'+m.ordner+'/'+unterordner:'_Unzugeordnet',\n      zielordner_id: zielordner_id,\n      neuer_dateiname: datum+'_'+absender+'_'+ai.dokumenttyp+'_CHF'+ai.betrag+'.pdf',\n      drive_file_id: driveFileId,\n      matched: !!m,\n      email_subject: emailSubject,\n      verarbeitet_am: new Date().toISOString().split('T')[0]\n    }});\n  } catch(e) {\n    results.push({json:{\n      dokumenttyp:'unbekannt', absender:'Parse-Fehler', empfaenger:'',\n      betrag:null, datum:null, faellig_bis:null, referenz:null,\n      zusammenfassung:'Fehler: '+e.message, konfidenz:0,\n      mandant_name:'UNBEKANNT', sachbearbeiter:'Unbekannt',\n      sachbearbeiter_email:'your-email@example.com',\n      zielordner:'_Unzugeordnet', zielordner_id:UNZUGEORDNET_ID,\n      neuer_dateiname:'fehler_item_'+i+'.pdf',\n      drive_file_id:(uploadItems[i] && uploadItems[i].json.id)||'',\n      matched:false, email_subject:'', verarbeitet_am:new Date().toISOString().split('T')[0]\n    }});\n  }\n}\n\nreturn results;",
        "mode": "runOnceForAllItems"
      },
      "id": "mandant-01",
      "name": "\ud83d\udd0d Mandant zuordnen",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1540,
        304
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": ""
          },
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ $json.matched }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-match-01",
      "name": "\u2705 Mandant erkannt?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1760,
        304
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID",
          "cachedResultName": "Belegjournal - demo-treuhand Treuhand (Demo)"
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultName": "Belegjournal"
        },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {}
        },
        "options": {}
      },
      "id": "sheets-01",
      "name": "\ud83d\udcca Belegjournal",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        2200,
        204
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "gmail-get-01",
      "name": "\ud83d\udce5 Attachment laden",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        500,
        304
      ],
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "parameters": {
        "operation": "get",
        "messageId": "={{ $json.id }}",
        "simple": false,
        "options": {
          "downloadAttachments": true
        }
      }
    },
    {
      "id": "manual-trigger-01",
      "name": "Manueller Start",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        60,
        304
      ],
      "parameters": {}
    },
    {
      "parameters": {
        "inputDataFieldName": "attachment_0",
        "name": "={{ $binary.attachment_0.fileName || 'beleg.pdf' }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_DRIVE_FOLDER_ID"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1000,
        304
      ],
      "id": "b2b8dc1f-e7f5-4a40-b05f-1e35ac6ffda1",
      "name": "\ud83d\udce4 In Unverarbeitet ablegen",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "move",
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.drive_file_id }}"
        },
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.zielordner_id }}"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1980,
        204
      ],
      "id": "cee813b6-9aaf-4ad9-be5f-72918e417597",
      "name": "\ud83d\udcc1 In Mandantenordner verschieben",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "move",
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.drive_file_id }}"
        },
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_DRIVE_FOLDER_ID"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1980,
        404
      ],
      "id": "4ff8241a-fd2b-4836-938c-97b14cb9a02c",
      "name": "\ud83d\udea8 In Unzugeordnet verschieben",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\nconst attachItems = $('\ud83d\udce5 Attachment laden').all();\nreturn items.map((item, i) => ({\n  json: item.json,\n  binary: attachItems[i] ? attachItems[i].binary : {}\n}));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        830,
        304
      ],
      "id": "YOUR_DRIVE_FOLDER_ID",
      "name": "\ud83d\udd17 Binary wiederherstellen"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const uploadItems = $input.all();\nconst pdfItems = $('\ud83d\udcc4 PDF Text extrahieren').all();\nconst attachItems = $('\ud83d\udce5 Attachment laden').all();\nconst results = [];\n\nfor (let i = 0; i < uploadItems.length; i++) {\n  const pdfText = (pdfItems[i] && pdfItems[i].json.text) || '';\n  const subject = (attachItems[i] && attachItems[i].json.subject) || '';\n  \n  const body = {\n    model: \"claude-sonnet-4-20250514\",\n    max_tokens: 600,\n    messages: [{\n      role: \"user\",\n      content: \"Du bist ein Schweizer Treuhand-Assistent. Analysiere diesen Beleg und extrahiere als reines JSON (kein Markdown, keine Erklaerung, NUR JSON).\\n\\nFelder: dokumenttyp (rechnung|lohnabrechnung|quittung|spesenabrechnung|steuerabrechnung|versicherung), absender, empfaenger, betrag (Zahl), datum (YYYY-MM-DD), faellig_bis (YYYY-MM-DD oder null), referenz, zusammenfassung (Einzeiler), konfidenz (0-1)\\n\\nEmail-Betreff: \" + subject + \"\\n\\nBeleg-Text:\\n\" + pdfText\n    }]\n  };\n  \n  results.push({json: {\n    apiBody: JSON.stringify(body),\n    driveId: uploadItems[i].json.id || '',\n    driveName: uploadItems[i].json.name || ''\n  }});\n}\n\nreturn results;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        304
      ],
      "id": "482e8d8e-a9e0-4b65-8df4-990e38061646",
      "name": "\ud83d\udd27 AI Request vorbereiten"
    },
    {
      "parameters": {
        "mode": "manual",
        "duplicateItem": false,
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "datum",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.datum }}",
              "type": "string"
            },
            {
              "id": "a2",
              "name": "absender",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.absender }}",
              "type": "string"
            },
            {
              "id": "a3",
              "name": "empfaenger",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.empfaenger }}",
              "type": "string"
            },
            {
              "id": "a4",
              "name": "dokumenttyp",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.dokumenttyp }}",
              "type": "string"
            },
            {
              "id": "a5",
              "name": "betrag",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.betrag }}",
              "type": "string"
            },
            {
              "id": "a6",
              "name": "referenz",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.referenz }}",
              "type": "string"
            },
            {
              "id": "a7",
              "name": "faellig_bis",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.faellig_bis }}",
              "type": "string"
            },
            {
              "id": "a8",
              "name": "mandant_name",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.mandant_name }}",
              "type": "string"
            },
            {
              "id": "a9",
              "name": "sachbearbeiter",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.sachbearbeiter }}",
              "type": "string"
            },
            {
              "id": "a10",
              "name": "zielordner",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.zielordner }}",
              "type": "string"
            },
            {
              "id": "a11",
              "name": "konfidenz",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.konfidenz }}",
              "type": "string"
            },
            {
              "id": "a12",
              "name": "zusammenfassung",
              "value": "={{ $('\ud83d\udd0d Mandant zuordnen').item.json.zusammenfassung }}",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": false
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2000,
        204
      ],
      "id": "set-belegdaten-1776007836745",
      "name": "\ud83d\udccb Belegdaten aufbereiten"
    },
    {
      "id": "mark-read-01",
      "name": "\u2714\ufe0f Als gelesen markieren",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        660,
        460
      ],
      "parameters": {
        "operation": "markAsRead",
        "messageId": "={{ $json.id }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Manueller Start": {
      "main": [
        [
          {
            "node": "\ud83d\udce7 Email Eingang",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce7 Email Eingang": {
      "main": [
        [
          {
            "node": "\ud83d\udce5 Attachment laden",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce5 Attachment laden": {
      "main": [
        [
          {
            "node": "\u2714\ufe0f Als gelesen markieren",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83d\udcc4 PDF Text extrahieren",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcc4 PDF Text extrahieren": {
      "main": [
        [
          {
            "node": "\ud83d\udd17 Binary wiederherstellen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd17 Binary wiederherstellen": {
      "main": [
        [
          {
            "node": "\ud83d\udce4 In Unverarbeitet ablegen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce4 In Unverarbeitet ablegen": {
      "main": [
        [
          {
            "node": "\ud83d\udd27 AI Request vorbereiten",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd27 AI Request vorbereiten": {
      "main": [
        [
          {
            "node": "\ud83e\udd16 AI Klassifikation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83e\udd16 AI Klassifikation": {
      "main": [
        [
          {
            "node": "\ud83d\udd0d Mandant zuordnen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd0d Mandant zuordnen": {
      "main": [
        [
          {
            "node": "\u2705 Mandant erkannt?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2705 Mandant erkannt?": {
      "main": [
        [
          {
            "node": "\ud83d\udcc1 In Mandantenordner verschieben",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\ud83d\udea8 In Unzugeordnet verschieben",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcc1 In Mandantenordner verschieben": {
      "main": [
        [
          {
            "node": "\ud83d\udccb Belegdaten aufbereiten",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udccb Belegdaten aufbereiten": {
      "main": [
        [
          {
            "node": "\ud83d\udcca Belegjournal",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  },
  "staticData": null
}