{
  "schema": "ldwf",
  "version": 1,
  "name": "Rechnungsverarbeitung",
  "meta": {
    "exportedAt": "2025-11-16T17:23:43.268Z",
    "exporter": "client"
  },
  "graph": {
    "nodes": [
      {
        "type": "trigger",
        "data": {
          "comment": "📧 SCHRITT 1: E-Mail-Empfang mit Rechnungs-PDF\n\n🎯 BESCHREIBUNG:\nDieser Trigger startet den Workflow automatisch, wenn eine neue E-Mail mit einer Rechnung als PDF-Anhang empfangen wird.\n\n⚙️ SETUP:\n1. Gmail-Verbindung ist bereits konfiguriert\n2. Suchfilter definieren, z.B.:\n   - subject:Rechnung has:attachment\n   - from:lieferant@example.com has:attachment filename:pdf\n   - label:rechnungen has:attachment\n\n🔧 PERSONALISIERUNGSOPTIONEN:\n• Filter nach bestimmten Absendern einschränken\n• Nur E-Mails mit bestimmten Betreffzeilen verarbeiten\n• Label-basierte Filterung nutzen (z.B. automatische Gmail-Regeln)\n• Zeitbasierte Filter (z.B. nur Geschäftszeiten)\n• Größenbeschränkung für Anhänge definieren\n\n💡 TIPP:\nVerwenden Sie Gmail-Label, um Rechnungen automatisch vorzufiltern und falsch-positive Treffer zu vermeiden.",
          "errorHandling": {
            "strategy": "stop"
          },
          "slug": "invoiceEmail",
          "kind": "integration",
          "integrationId": "0ccd0103-2862-46ac-86e1-ef1b40e679b4",
          "triggerId": "5876ca57-6b3f-496a-83ea-e4b5a589be39",
          "requiresConnection": true,
          "connectionId": null,
          "params": []
        },
        "id": "7bc27fb8-b579-4b2c-af4d-eeb957cbd7d7",
        "position": {
          "x": 20,
          "y": 11800
        }
      },
      {
        "type": "agent",
        "data": {
          "comment": "🤖 SCHRITT 2: KI-gestützte Datenextraktion aus Rechnung\n\n🎯 BESCHREIBUNG:\nEin AI-Agent analysiert das PDF-Dokument und extrahiert automatisch alle relevanten Rechnungsdaten in strukturierter Form. Unterstützt auch gescannte/OCR-Dokumente.\n\n⚙️ SETUP:\n1. Agent nutzt das Standard-LLM-Modell für Textextraktion\n2. Strukturiertes Output-Schema definiert 10 Felder:\n   - Rechnungsnummer, Lieferant, Beträge (Netto/Brutto)\n   - Datum, Beschreibung, MwSt.-Satz & Betrag\n   - Output-Zusammenfassung & Erfolgs-Flag\n3. OCR-Fähigkeit ist automatisch aktiviert\n\n🔧 PERSONALISIERUNGSOPTIONEN:\n• Weitere Felder hinzufügen (z.B. Bestellnummer, Liefertermin, Zahlungsziel)\n• Validierungsregeln im Prompt ergänzen (z.B. Datumsformat prüfen)\n• Sprachunterstützung erweitern (mehrsprachige Rechnungen)\n• Kostenstellen-Extraktion aktivieren\n• Bankverbindung des Lieferanten erfassen\n• Positionsdetails extrahieren (Einzelposten der Rechnung)\n\n💡 TIPP:\nFür bessere Genauigkeit bei komplexen Rechnungen können Sie spezifische Beispiele im Prompt hinzufügen oder ein stärkeres Modell wählen.",
          "errorHandling": {
            "strategy": "stop"
          },
          "slug": "extractInvoiceData",
          "assistantId": null,
          "mode": "create",
          "name": "Rechnungsdaten extrahieren",
          "prompt": {
            "mode": "manual",
            "value": "Analysiere die beigefügte Rechnung (PDF) und extrahiere alle relevanten Daten.\n\nDie Rechnung findest du in den Anhängen der E-Mail: {{invoiceEmail.output}}\n\nExtrahiere folgende Informationen präzise:\n- Rechnungsnummer\n- Lieferant/Absender\n- Rechnungsbetrag (Netto und Brutto)\n- Rechnungsdatum\n- Leistungsbeschreibung\n- Mehrwertsteuersatz und -betrag\n\nAchte auf:\n- Korrekte Zahlenformate (nutze Punkt als Dezimaltrennzeichen)\n- Vollständige Extrahierung aller Felder\n- Bei gescannten Rechnungen: OCR-Fehler korrigieren"
          },
          "attachmentIds": [],
          "output": "structured",
          "connectionOverrides": {},
          "outputSchema": [
            {
              "id": "d06f78b6-0dc7-4a45-8268-019943ea770d",
              "name": "invoice_number",
              "description": "Die Rechnungsnummer",
              "type": "string",
              "required": true
            },
            {
              "id": "445d73f2-69d7-4ce9-9a51-0e45b9a2c7c5",
              "name": "supplier",
              "description": "Name des Lieferanten/Absenders",
              "type": "string",
              "required": true
            },
            {
              "id": "d9013a78-b259-4711-aad1-fc4feb4627ba",
              "name": "amount_net",
              "description": "Nettobetrag der Rechnung",
              "type": "number",
              "required": true
            },
            {
              "id": "9713d1c6-1e1b-448e-aad0-e64a37e7e971",
              "name": "amount_gross",
              "description": "Bruttobetrag der Rechnung",
              "type": "number",
              "required": true
            },
            {
              "id": "f2260ac9-fe20-4ca9-b88b-200c66da573d",
              "name": "invoice_date",
              "description": "Rechnungsdatum (Format: YYYY-MM-DD)",
              "type": "string",
              "required": true
            },
            {
              "id": "59ae9d97-2b88-4b0f-9c28-a0580e1fc33f",
              "name": "description",
              "description": "Leistungsbeschreibung",
              "type": "string",
              "required": true
            },
            {
              "id": "cea2943b-64da-4642-9b74-1b81f79ae40a",
              "name": "vat_rate",
              "description": "Mehrwertsteuersatz in Prozent",
              "type": "number",
              "required": true
            },
            {
              "id": "c6e85ec6-63ab-44e0-9fdd-1b09868a47a6",
              "name": "vat_amount",
              "description": "Mehrwertsteuerbetrag",
              "type": "number",
              "required": true
            },
            {
              "id": "1c5255bb-5934-431f-a873-ab2213c53c49",
              "name": "output",
              "description": "Zusammenfassung der extrahierten Daten",
              "type": "string",
              "required": true
            },
            {
              "id": "cc5f0751-ec9a-42c2-9cde-bd5c06385456",
              "name": "success",
              "description": "Ob die Extraktion erfolgreich war",
              "type": "boolean",
              "required": true
            }
          ],
          "modelId": "c968689a-c0d9-49de-aa76-b10ed15ebb0e",
          "tools": [],
          "maxSteps": 25
        },
        "id": "7d44ee2e-77aa-4be1-b02d-d0af42a42eeb",
        "position": {
          "x": 560,
          "y": 11800
        }
      },
      {
        "type": "code",
        "data": {
          "comment": "📋 SCHRITT 3: ERP-Datenabgleich mit Toleranzprüfung\n\n🎯 BESCHREIBUNG:\nVergleicht die extrahierten Rechnungsdaten mit den Bestelldaten aus dem ERP-System. Prüft Lieferant, Betrag (mit konfigurierbarer Toleranz) und Leistungsbeschreibung. Identifiziert und kategorisiert Abweichungen nach Schweregrad.\n\n⚙️ SETUP:\n1. Aktuell: Simulierte ERP-Daten für Demo-Zwecke\n2. Für Produktion: Ersetzen Sie den Code durch echten API-Call\n3. Toleranzwert: 5% Betragsabweichung (anpassbar)\n4. Schweregrade: 'high' (Lieferant/Betrag), 'medium' (Beschreibung)\n\n🔧 PERSONALISIERUNGSOPTIONEN:\n• Toleranzwert anpassen (aktuell 5%, Zeile 15)\n• ERP-API-Endpunkt konfigurieren (z.B. SAP, Microsoft Dynamics, Odoo)\n• Zusätzliche Prüfkriterien hinzufügen:\n  - Bestellnummer-Abgleich\n  - Lieferdatum-Validierung\n  - Kostenstellen-Prüfung\n  - Budgetüberschreitungs-Check\n• Schweregrad-Logik anpassen (z.B. geringe Abweichungen ignorieren)\n• Whitelist für vertrauenswürdige Lieferanten\n• Automatische Freigabe unter bestimmten Schwellenwerten\n\n💡 PRODUKTIV-INTEGRATION:\nErsetzen Sie Zeile 8-13 durch:\nconst response = await ld.request({\n  url: 'https://ihr-erp-system.de/api/orders',\n  method: 'GET',\n  headers: { 'Authorization': 'Bearer YOUR_API_KEY' }\n});\nconst erpOrderData = response.json;",
          "errorHandling": {
            "strategy": "stop"
          },
          "name": "ERP-Abgleich",
          "slug": "erpComparison",
          "language": "javascript",
          "code": "// Simuliertes ERP-System: Bestelldaten abrufen\n// In Produktion: API-Call zum echten ERP-System\n\nconst invoiceData = extractInvoiceData.output.structured;\n\n// Simulierte ERP-Bestelldaten (Beispiel)\nconst erpOrderData = {\n  \"supplier\": invoiceData.supplier,\n  \"expected_amount\": invoiceData.amount_gross * 0.98, // 2% Toleranz simuliert\n  \"order_description\": invoiceData.description,\n  \"order_date\": \"2024-01-15\"\n};\n\n// Toleranzwert für Betragsabweichungen (5%)\nconst TOLERANCE_PERCENT = 5;\nconst tolerance = erpOrderData.expected_amount * (TOLERANCE_PERCENT / 100);\n\n// Abgleich durchführen\nconst discrepancies = [];\n\n// Lieferant prüfen\nif (invoiceData.supplier !== erpOrderData.supplier) {\n  discrepancies.push({\n    field: \"Lieferant\",\n    invoice_value: invoiceData.supplier,\n    erp_value: erpOrderData.supplier,\n    severity: \"high\"\n  });\n}\n\n// Betrag prüfen (mit Toleranz)\nconst amountDiff = Math.abs(invoiceData.amount_gross - erpOrderData.expected_amount);\nif (amountDiff > tolerance) {\n  discrepancies.push({\n    field: \"Betrag\",\n    invoice_value: invoiceData.amount_gross,\n    erp_value: erpOrderData.expected_amount,\n    difference: amountDiff,\n    severity: \"high\"\n  });\n}\n\n// Leistungsbeschreibung prüfen (vereinfachte Prüfung)\nif (!invoiceData.description.toLowerCase().includes(erpOrderData.order_description.toLowerCase().split(' ')[0])) {\n  discrepancies.push({\n    field: \"Leistungsbeschreibung\",\n    invoice_value: invoiceData.description,\n    erp_value: erpOrderData.order_description,\n    severity: \"medium\"\n  });\n}\n\nreturn {\n  has_discrepancies: discrepancies.length > 0,\n  discrepancy_count: discrepancies.length,\n  discrepancies: discrepancies,\n  invoice_data: invoiceData,\n  erp_data: erpOrderData,\n  tolerance_percent: TOLERANCE_PERCENT\n};"
        },
        "id": "e6646a3e-3ab1-46cb-87aa-3091295e2381",
        "position": {
          "x": 1120,
          "y": 11800
        }
      },
      {
        "type": "condition",
        "data": {
          "comment": "❓ SCHRITT 4: Verzweigung basierend auf Prüfergebnis\n\n🎯 BESCHREIBUNG:\nEntscheidungsknoten, der den Workflow in zwei Pfade aufteilt:\n- Pfad A: Abweichungen gefunden → Manuelle Prüfung erforderlich\n- Pfad B: Keine Abweichungen → Automatische Buchung\n\n⚙️ SETUP:\n1. Bedingung 1: \"Abweichungen gefunden\" (has_discrepancies === true)\n   → Führt zu Slack-Benachrichtigung\n2. Bedingung 2: \"Keine Abweichungen\" (has_discrepancies === false)\n   → Führt zu automatischer Buchhaltungsbuchung\n3. Modus: Manual (direkte JavaScript-Auswertung)\n4. Output-Modus: Single (nur ein Pfad wird ausgeführt)\n\n🔧 PERSONALISIERUNGSOPTIONEN:\n• Mehrere Schweregrad-Stufen einführen:\n  - Kritisch: Sofortige Benachrichtigung + Workflow-Stopp\n  - Mittel: Benachrichtigung + Manuelle Freigabe\n  - Gering: Automatische Buchung + Info-Mail\n• Betragsabhängige Logik (z.B. Kleinbeträge immer freigeben)\n• Lieferantenabhängige Regeln (vertrauenswürdige Lieferanten)\n• Zeitabhängige Verzweigung (Dringlichkeit prüfen)\n• Kombinierte Bedingungen (mehrere Kriterien gleichzeitig)\n\n💡 TIPP:\nFür komplexere Entscheidungslogik können Sie zusätzliche Bedingungen hinzufügen oder den Modus auf 'prompt' ändern, um KI-basierte Entscheidungen zu ermöglichen.",
          "errorHandling": {
            "strategy": "stop"
          },
          "name": "Abweichungen prüfen",
          "slug": "checkDiscrepancies",
          "mode": "manual",
          "outputMode": "single",
          "modelId": "64776bd9-4c58-42d0-8301-2c8a4566e68c",
          "forceSelectBranch": false,
          "conditions": [
            {
              "id": "bbcac2af-abc6-4ca2-a028-c78f6733be18",
              "name": "Abweichungen gefunden",
              "value": "{{erpComparison.output.has_discrepancies === true}}",
              "prompt": null
            },
            {
              "id": "3f2ee6bd-61ca-403e-bb8a-6ee4f6f4cff2",
              "name": "Keine Abweichungen",
              "value": "{{erpComparison.output.has_discrepancies === false}}",
              "prompt": null
            }
          ]
        },
        "id": "9d78123d-b1ac-49d4-b4b9-6b1166881f7c",
        "position": {
          "x": 1680,
          "y": 11800
        }
      },
      {
        "type": "action",
        "data": {
          "comment": "🚨 SCHRITT 5A: Benachrichtigung bei Abweichungen\n\n🎯 BESCHREIBUNG:\nSendet eine formatierte Slack-Nachricht an das Buchhaltungsteam, wenn Abweichungen zwischen Rechnung und ERP-System erkannt wurden. Enthält alle relevanten Details zur manuellen Prüfung.\n\n⚙️ SETUP:\n1. Integration: Slack \"Nachricht senden\"\n2. Nachrichtenformat: Strukturiert mit Emojis und Markdown\n3. Kanal: Wird automatisch ausgewählt (Prompt-Modus)\n4. Inhalt:\n   - Rechnungskopfdaten (Nummer, Lieferant, Betrag, Datum)\n   - Anzahl und Details der Abweichungen\n   - Handlungsaufforderung zur manuellen Prüfung\n\n🔧 PERSONALISIERUNGSOPTIONEN:\n• Kanal fest definieren (z.B. #buchhaltung, #rechnungen)\n• Benachrichtigungsformat anpassen:\n  - @mentions für zuständige Personen hinzufügen\n  - Slack-Blocks für interaktive Buttons (Freigeben/Ablehnen)\n  - Farbcodierung nach Schweregrad\n• Alternative Benachrichtigungskanäle:\n  - E-Mail (statt/zusätzlich zu Slack)\n  - Microsoft Teams\n  - SMS für kritische Fälle\n• Eskalationslogik: Wiederholte Benachrichtigung nach X Stunden\n• PDF-Anhang der Original-Rechnung hinzufügen\n• Link zu Freigabe-Formular einfügen\n\n💡 TIPP:\nVerwenden Sie Slack-Workflows oder Buttons, um direkt aus der Nachricht heraus Freigaben zu erteilen oder Rückfragen zu stellen.",
          "errorHandling": {
            "strategy": "stop"
          },
          "slug": "notifyDiscrepancies",
          "actionId": "26a39d11-d5fe-4f46-b776-973dd20b8147",
          "config": {
            "connectionId": null,
            "requiresConfirmation": false,
            "modelId": "c968689a-c0d9-49de-aa76-b10ed15ebb0e",
            "fields": {
              "text": {
                "mode": "manual",
                "value": "⚠️ *Rechnungsabweichung erkannt*\n\n*Rechnung:* {{extractInvoiceData.output.structured.invoice_number}}\n*Lieferant:* {{extractInvoiceData.output.structured.supplier}}\n*Rechnungsdatum:* {{extractInvoiceData.output.structured.invoice_date}}\n*Bruttobetrag:* €{{extractInvoiceData.output.structured.amount_gross}}\n\n*Anzahl Abweichungen:* {{erpComparison.output.discrepancy_count}}\n\n*Details:*\n{{erpComparison.output.discrepancies}}\n\n_Bitte prüfen Sie die Rechnung manuell und nehmen Sie ggf. Rücksprache mit dem Lieferanten._",
                "prompt": null
              },
              "channelId": {
                "mode": "prompt",
                "value": null,
                "prompt": "Wähle den Buchhaltungs-Kanal oder Channel für Rechnungsabweichungen"
              }
            }
          }
        },
        "id": "0c3f2d34-16c2-41c3-9fdc-cacf73340ac8",
        "position": {
          "x": 2240,
          "y": 11610
        }
      },
      {
        "type": "code",
        "data": {
          "comment": "✅ SCHRITT 5B: Automatische Buchhaltungsbuchung\n\n🎯 BESCHREIBUNG:\nErstellt automatisch einen Buchhaltungseintrag im Finanzsystem, wenn keine Abweichungen gefunden wurden. Bereitet alle Buchungsdaten strukturiert auf und überträgt sie an das Buchhaltungssystem (DATEV, Lexware, etc.).\n\n⚙️ SETUP:\n1. Aktuell: Simulierte Buchung für Demo-Zwecke\n2. Für Produktion: Ersetzen Sie durch echten API-Call zum Buchhaltungssystem\n3. Buchungslogik:\n   - Debit-Konto: 4400 (Wareneingang)\n   - Credit-Konto: 1600 (Verbindlichkeiten)\n   - Vorsteuer-Konto: 1576 (Vorsteuer)\n4. Automatische Entry-ID-Generierung mit Zeitstempel\n\n🔧 PERSONALISIERUNGSOPTIONEN:\n• Kontenplan anpassen (SKR03, SKR04, oder individuell):\n  - Verschiedene Aufwandskonten je nach Kategorie\n  - Kostenstellenzuordnung automatisieren\n  - Projektbuchungen unterstützen\n• Buchhaltungssystem-Integration:\n  - DATEV API anbinden\n  - Lexware, sevDesk, oder andere Tools\n  - SAP FI-Modul\n• Zusätzliche Validierungen:\n  - Dubletten-Prüfung (Rechnungsnummer bereits gebucht?)\n  - Budgetprüfung vor Buchung\n  - Freigabe-Workflow für Beträge > X€\n• Archivierung:\n  - PDF in DMS speichern (z.B. SharePoint, Dropbox)\n  - GoBD-konforme Archivierung\n• Bestätigungsmail an Absender/Empfänger\n\n💡 PRODUKTIV-INTEGRATION:\nErsetzen Sie ab Zeile 35 durch:\nconst response = await ld.request({\n  url: 'https://api.buchhaltungssystem.de/entries',\n  method: 'POST',\n  headers: {\n    'Authorization': 'Bearer YOUR_API_KEY',\n    'Content-Type': 'application/json'\n  },\n  body: accountingEntry\n});\nreturn response.json;",
          "errorHandling": {
            "strategy": "stop"
          },
          "name": "Buchhaltungseintrag erstellen",
          "slug": "createAccountingEntry",
          "language": "javascript",
          "code": "// Simulierter Buchhaltungseintrag\n// In Produktion: API-Call zum echten Buchhaltungssystem (z.B. DATEV, Lexware, etc.)\n\nconst invoiceData = extractInvoiceData.output.structured;\n\n// Buchungsdaten vorbereiten\nconst accountingEntry = {\n  entry_id: `ACC-${Date.now()}`,\n  invoice_number: invoiceData.invoice_number,\n  supplier: invoiceData.supplier,\n  invoice_date: invoiceData.invoice_date,\n  booking_date: new Date().toISOString().split('T')[0],\n  \n  // Beträge\n  amount_net: invoiceData.amount_net,\n  amount_gross: invoiceData.amount_gross,\n  vat_amount: invoiceData.vat_amount,\n  vat_rate: invoiceData.vat_rate,\n  \n  // Beschreibung\n  description: invoiceData.description,\n  \n  // Buchungskonten (Beispiel-Mapping)\n  debit_account: \"4400\", // Wareneingang\n  credit_account: \"1600\", // Verbindlichkeiten\n  vat_account: \"1576\", // Vorsteuer\n  \n  // Status\n  status: \"booked\",\n  verified: true,\n  auto_processed: true,\n  \n  // Zeitstempel\n  created_at: new Date().toISOString()\n};\n\n// Simuliere API-Call zum Buchhaltungssystem\nld.log(`Buchhaltungseintrag erstellt: ${accountingEntry.entry_id}`);\nld.log(`Rechnung ${invoiceData.invoice_number} wurde automatisch gebucht`);\n\n// In Produktion würde hier der echte API-Call stattfinden:\n// const response = await ld.request({\n//   url: 'https://api.buchhaltungssystem.de/entries',\n//   method: 'POST',\n//   headers: {\n//     'Authorization': 'Bearer YOUR_API_KEY',\n//     'Content-Type': 'application/json'\n//   },\n//   body: accountingEntry\n// });\n\nreturn {\n  success: true,\n  message: `Rechnung ${invoiceData.invoice_number} erfolgreich gebucht`,\n  entry: accountingEntry,\n  invoice_data: invoiceData\n};"
        },
        "id": "83f9fe22-67f9-448d-b3c4-8dfc4c3d242c",
        "position": {
          "x": 2240,
          "y": 11990
        }
      }
    ],
    "edges": [
      {
        "id": "13cbfae8-d23c-4a25-bde2-ce039b375207",
        "source": "7bc27fb8-b579-4b2c-af4d-eeb957cbd7d7",
        "target": "7d44ee2e-77aa-4be1-b02d-d0af42a42eeb",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      },
      {
        "id": "728ac6ca-b165-4fec-b74c-e15fc1dec565",
        "source": "7d44ee2e-77aa-4be1-b02d-d0af42a42eeb",
        "target": "e6646a3e-3ab1-46cb-87aa-3091295e2381",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      },
      {
        "id": "bc3cc886-1dd0-46f6-8c23-7508fafb9bfb",
        "source": "e6646a3e-3ab1-46cb-87aa-3091295e2381",
        "target": "9d78123d-b1ac-49d4-b4b9-6b1166881f7c",
        "animated": false,
        "sourceHandle": "output-success",
        "targetHandle": "input-default",
        "conditionId": null
      },
      {
        "id": "405e83b3-6a00-48ed-9b73-4f93d801dd04",
        "source": "9d78123d-b1ac-49d4-b4b9-6b1166881f7c",
        "target": "0c3f2d34-16c2-41c3-9fdc-cacf73340ac8",
        "animated": false,
        "sourceHandle": "output-condition",
        "targetHandle": "input-default",
        "conditionId": "bbcac2af-abc6-4ca2-a028-c78f6733be18"
      },
      {
        "id": "94f88a18-b232-451c-9132-22102c18c32a",
        "source": "9d78123d-b1ac-49d4-b4b9-6b1166881f7c",
        "target": "83f9fe22-67f9-448d-b3c4-8dfc4c3d242c",
        "animated": false,
        "sourceHandle": "output-condition",
        "targetHandle": "input-default",
        "conditionId": "3f2ee6bd-61ca-403e-bb8a-6ee4f6f4cff2"
      }
    ]
  }
}