{
  "name": "Papierkram-Autopilot – 3 Monatsübersicht",
  "nodes": [
    {
      "name": "Notiz: Start",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -460,
        -440
      ],
      "parameters": {
        "content": "# 📊 Monatsübersicht\n**Papierkram-Autopilot v1.0.2**\n\nLiest `Belegliste.csv` und schreibt nach `Berichte/`:\n- `Monatsuebersicht_JJJJ-MM.md` (Anzahl, Summe, je Kategorie & Lieferant, Einzelbelege, offene Prüffälle)\n- `Monatsuebersicht_JJJJ-MM.csv` (für Excel / Steuerbüro)\n\n### Einrichtung\n1. **Einstellungen** → `basisOrdner` (gleich wie Workflow 1).\n2. `monat` leer lassen = **Vormonat**; oder fest z. B. `2026-09`.\n3. Aktiv schalten → läuft am 1. jedes Monats um 7 Uhr.\n\n📧 Der Node **Bericht per E-Mail (optional)** ist **deaktiviert**. Zum Nutzen: SMTP-Zugangsdaten anlegen, Adressen eintragen, Node aktivieren.\n\n> Arbeitshilfe, keine Steuerberatung.",
        "width": 520,
        "height": 520,
        "color": 4
      },
      "id": "042419d2-8037-4467-a5ba-b2f7a0b9c426"
    },
    {
      "name": "Manuell starten",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        -420,
        140
      ],
      "parameters": {},
      "id": "8e7ed9a6-3e7c-47d5-ac34-ca496da799a6"
    },
    {
      "name": "Monatlich am 1.",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -420,
        320
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "months",
              "monthsInterval": 1,
              "triggerAtDayOfMonth": 1,
              "triggerAtHour": 7
            }
          ]
        }
      },
      "id": "314eba1f-8b6b-4f25-adc0-33cff00e5f72"
    },
    {
      "name": "Einstellungen",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -200,
        220
      ],
      "parameters": {
        "mode": "manual",
        "includeOtherFields": false,
        "assignments": {
          "assignments": [
            {
              "id": "2df0d44e-8e6b-495a-a679-a086045d7970",
              "name": "basisOrdner",
              "value": "/home/node/.n8n-files/Papierkram",
              "type": "string"
            },
            {
              "id": "35b6d26d-5e0c-4597-a21b-0184366cceae",
              "name": "monat",
              "value": "",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "notes": "monat: leer = Vormonat, sonst JJJJ-MM",
      "notesInFlow": true,
      "id": "b71d5088-bc9b-4c34-a3f8-b9f3b9a02c2f"
    },
    {
      "name": "Belegliste lesen",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1.1,
      "position": [
        20,
        220
      ],
      "parameters": {
        "fileSelector": "={{ $('Einstellungen').first().json.basisOrdner.replace(/\\\\/g, '/').replace(/\\/+$/, '') + '/Belegliste.csv' }}",
        "options": {}
      },
      "alwaysOutputData": true,
      "onError": "continueRegularOutput",
      "id": "0a18771b-226b-4945-ad4b-6e530590282a"
    },
    {
      "name": "Belegliste als Text",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1.1,
      "position": [
        240,
        220
      ],
      "parameters": {
        "operation": "text",
        "binaryPropertyName": "data",
        "destinationKey": "data",
        "options": {
          "stripBOM": true
        }
      },
      "onError": "continueRegularOutput",
      "id": "e2a68aa3-314e-4cab-a2a0-2b80d51b832b"
    },
    {
      "name": "Monat auswerten",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        220
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "// ===== Code-Node \"Monat auswerten\" (Modus: Run Once for All Items) =====\n// Liest die Belegliste und erstellt eine Monatsuebersicht (Markdown + CSV).\n// Monat: Feld \"monat\" in \"Einstellungen\" (Format JJJJ-MM). Leer = Vormonat.\n\nconst cfg = $('Einstellungen').first().json;\nconst roh = String($('Belegliste als Text').first().json.data || '').replace(/^﻿/, '');\n\nfunction pad(n) { return String(n).padStart(2, '0'); }\nfunction zahl(s) { const t = String(s || '').replace(/\\./g, '').replace(',', '.'); const n = parseFloat(t); return isNaN(n) ? 0 : n; }\nfunction eur(n) { return n.toFixed(2).replace('.', ',').replace(/\\B(?=(\\d{3})+(?!\\d))/g, '.') + ' €'; }\nfunction eurCsv(n) { return n.toFixed(2).replace('.', ','); }\nfunction csvFeld(v) { const s = String(v); return /[;\"\\r\\n]/.test(s) ? '\"' + s.replace(/\"/g, '\"\"') + '\"' : s; }\n\n// CSV mit Anfuehrungszeichen korrekt zerlegen\nfunction zerlege(zeile) {\n  const out = []; let cur = ''; let q = false;\n  for (let i = 0; i < zeile.length; i++) {\n    const c = zeile[i];\n    if (q) { if (c === '\"' && zeile[i + 1] === '\"') { cur += '\"'; i++; } else if (c === '\"') q = false; else cur += c; }\n    else if (c === '\"') q = true; else if (c === ';') { out.push(cur); cur = ''; } else cur += c;\n  }\n  out.push(cur); return out;\n}\n\nlet monat = String(cfg.monat || '').trim();\nif (!/^\\d{4}-\\d{2}$/.test(monat)) {\n  const d = new Date(); d.setDate(1); d.setMonth(d.getMonth() - 1);\n  monat = `${d.getFullYear()}-${pad(d.getMonth() + 1)}`;\n}\n\nconst zeilen = roh.split(/\\r?\\n/).filter((z) => z.trim().length);\nconst kopf = zeilen.length ? zerlege(zeilen.shift()) : [];\nconst rows = zeilen.map((z) => { const f = zerlege(z); const o = {}; kopf.forEach((k, i) => { o[k] = f[i] || ''; }); return o; });\n\nconst imMonat = rows.filter((r) => r.Status === 'erkannt' && String(r.Datum).startsWith(monat));\nconst offen = rows.filter((r) => r.Status !== 'erkannt');\n\nfunction gruppiere(feld) {\n  const m = {};\n  for (const r of imMonat) { const k = r[feld] || '(leer)'; m[k] = m[k] || { anzahl: 0, summe: 0 }; m[k].anzahl++; m[k].summe += zahl(r.Betrag); }\n  return Object.entries(m).sort((a, b) => b[1].summe - a[1].summe);\n}\nconst proLieferant = gruppiere('Lieferant');\nconst proKategorie = gruppiere('Kategorie');\nconst gesamt = imMonat.reduce((s, r) => s + zahl(r.Betrag), 0);\n\nconst md = [];\nmd.push(`# Monatsübersicht ${monat}`);\nmd.push('');\nmd.push(`Erstellt am ${new Date().toISOString().slice(0, 10)} mit dem Papierkram-Autopilot. Grundlage: Belegliste (nur Belege mit Status „erkannt“).`);\nmd.push('');\nmd.push(`- **Anzahl Belege:** ${imMonat.length}`);\nmd.push(`- **Summe (Bruttobeträge laut Beleg):** ${eur(gesamt)}`);\nmd.push(`- **Belege mit Status „prüfen“ (alle Monate):** ${offen.length}`);\nmd.push('');\nmd.push('## Nach Kategorie');\nmd.push('');\nmd.push('| Kategorie | Anzahl | Summe |');\nmd.push('|---|---:|---:|');\nfor (const [k, v] of proKategorie) md.push(`| ${k} | ${v.anzahl} | ${eur(v.summe)} |`);\nmd.push('');\nmd.push('## Nach Lieferant');\nmd.push('');\nmd.push('| Lieferant | Anzahl | Summe |');\nmd.push('|---|---:|---:|');\nfor (const [k, v] of proLieferant) md.push(`| ${k} | ${v.anzahl} | ${eur(v.summe)} |`);\nmd.push('');\nmd.push('## Einzelbelege');\nmd.push('');\nmd.push('| Datum | Lieferant | Kategorie | Betrag | Datei |');\nmd.push('|---|---|---|---:|---|');\nfor (const r of imMonat.sort((a, b) => a.Datum.localeCompare(b.Datum))) md.push(`| ${r.Datum} | ${r.Lieferant} | ${r.Kategorie} | ${eur(zahl(r.Betrag))} | ${String(r.Ablage_Datei).split('/').pop()} |`);\nif (offen.length) {\n  md.push('');\n  md.push('## Bitte prüfen');\n  md.push('');\n  for (const r of offen) md.push(`- ${r.Original_Datei} → ${r.Ablage_Datei}`);\n}\nmd.push('');\nmd.push('> Hinweis: Diese Übersicht ist eine Arbeitshilfe und ersetzt keine Buchhaltung oder Steuerberatung. Beträge wurden automatisch erkannt – bitte stichprobenartig prüfen.');\nmd.push('');\n\nconst csvZeilen = ['Typ;Name;Anzahl;Summe'];\ncsvZeilen.push(['Gesamt', monat, imMonat.length, eurCsv(gesamt)].map(csvFeld).join(';'));\nfor (const [k, v] of proKategorie) csvZeilen.push(['Kategorie', k, v.anzahl, eurCsv(v.summe)].map(csvFeld).join(';'));\nfor (const [k, v] of proLieferant) csvZeilen.push(['Lieferant', k, v.anzahl, eurCsv(v.summe)].map(csvFeld).join(';'));\n\nconst basis = String(cfg.basisOrdner).replace(/\\\\/g, '/').replace(/\\/+$/, '');\nreturn [{\n  json: {\n    monat,\n    anzahl: imMonat.length,\n    summe: Math.round(gesamt * 100) / 100,\n    markdown: md.join('\\n'),\n    csv: '﻿' + csvZeilen.join('\\r\\n') + '\\r\\n',\n    pfad_md: `${basis}/Berichte/Monatsuebersicht_${monat}.md`,\n    pfad_csv: `${basis}/Berichte/Monatsuebersicht_${monat}.csv`,\n    betreff: `Monatsübersicht ${monat}: ${imMonat.length} Belege, ${eur(gesamt)}`,\n  },\n}];\n"
      },
      "id": "53b77905-825d-43bb-a98e-04e964185a52"
    },
    {
      "name": "Markdown als Datei",
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        700,
        120
      ],
      "parameters": {
        "operation": "toText",
        "sourceProperty": "markdown",
        "binaryPropertyName": "data",
        "options": {
          "fileName": "={{ 'Monatsuebersicht_' + $json.monat + '.md' }}",
          "encoding": "utf8"
        }
      },
      "id": "5acb70cd-a080-478f-a7b5-d1905fa1d80e"
    },
    {
      "name": "Bericht speichern (MD)",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1.1,
      "position": [
        920,
        120
      ],
      "parameters": {
        "operation": "write",
        "fileName": "={{ $('Monat auswerten').first().json.pfad_md }}",
        "dataPropertyName": "data",
        "options": {}
      },
      "id": "2d27ea64-94b5-463c-aa86-7a46ffdb78cc"
    },
    {
      "name": "CSV als Datei",
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        700,
        320
      ],
      "parameters": {
        "operation": "toText",
        "sourceProperty": "csv",
        "binaryPropertyName": "data",
        "options": {
          "fileName": "={{ 'Monatsuebersicht_' + $json.monat + '.csv' }}",
          "encoding": "utf8"
        }
      },
      "id": "3387d421-6b07-44a2-af1c-e86d7951267b"
    },
    {
      "name": "Bericht speichern (CSV)",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1.1,
      "position": [
        920,
        320
      ],
      "parameters": {
        "operation": "write",
        "fileName": "={{ $('Monat auswerten').first().json.pfad_csv }}",
        "dataPropertyName": "data",
        "options": {}
      },
      "id": "04550ca1-c93a-4368-ac80-6cd0ea0c4c2c"
    },
    {
      "name": "Bericht per E-Mail (optional)",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        1140,
        120
      ],
      "disabled": true,
      "parameters": {
        "fromEmail": "absender@example.com",
        "toEmail": "du@example.com",
        "subject": "={{ $('Monat auswerten').first().json.betreff }}",
        "emailFormat": "text",
        "text": "={{ $('Monat auswerten').first().json.markdown }}",
        "options": {}
      },
      "id": "252241b5-4991-4555-a270-76fdc7bcea3d"
    }
  ],
  "connections": {
    "Manuell starten": {
      "main": [
        [
          {
            "node": "Einstellungen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monatlich am 1.": {
      "main": [
        [
          {
            "node": "Einstellungen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Einstellungen": {
      "main": [
        [
          {
            "node": "Belegliste lesen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Belegliste lesen": {
      "main": [
        [
          {
            "node": "Belegliste als Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Belegliste als Text": {
      "main": [
        [
          {
            "node": "Monat auswerten",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monat auswerten": {
      "main": [
        [
          {
            "node": "Markdown als Datei",
            "type": "main",
            "index": 0
          },
          {
            "node": "CSV als Datei",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Markdown als Datei": {
      "main": [
        [
          {
            "node": "Bericht speichern (MD)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Bericht speichern (MD)": {
      "main": [
        [
          {
            "node": "Bericht per E-Mail (optional)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CSV als Datei": {
      "main": [
        [
          {
            "node": "Bericht speichern (CSV)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner"
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": false,
    "papierkramAutopilot": "1.0.2"
  },
  "tags": []
}
