{
  "name": "Zahlungserinnerungen für offene Rechnungen",
  "nodes": [
    {
      "id": "b6c8cdd1-732a-40ed-ad78-9ed56a68c1b7",
      "name": "Notiz 1",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -60,
        -520
      ],
      "parameters": {
        "content": "## So richtest du den Ablauf ein\n1. Mit **Test: Start per Klick** ausprobieren: Fünf erfundene Rechnungen laufen durch, nichts wird gesendet.\n2. In **Überfälligkeit prüfen** oben die Fristen und deine Texte anpassen.\n3. Echte Rechnungen: **Offene Rechnungen aus Lexware Office holen** mit einem API-Schlüssel (Tarif XL, Zugang \"Bearer Auth\") einrichten und einschalten. Ohne Lexware: die Rechnungen aus deiner Liste in denselben Aufbau bringen wie die Testdaten.\n4. Die E-Mail-Knoten einrichten und einschalten. Sie schicken die Entwürfe **an dich**, nie direkt an Kunden.\n5. Der Zeitplan läuft einmal pro Woche, so bekommt jede Rechnung höchstens einen Entwurf pro Woche.",
        "height": 320,
        "width": 560,
        "color": 4
      }
    },
    {
      "id": "d27b07d9-7219-482e-af73-8166fd12bad1",
      "name": "Test: Start per Klick",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        180
      ],
      "parameters": {},
      "notes": "Startet den Ablauf von Hand, zum Testen mit den Beispieldaten."
    },
    {
      "id": "b7fe982b-3e21-4b43-a3c0-bc7021d2e9be",
      "name": "Jeden Montag um 8 Uhr",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "weeksInterval": 1,
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 8
            }
          ]
        }
      },
      "notes": "Startet einmal pro Woche."
    },
    {
      "id": "76578436-604e-4532-a79e-572849f5d024",
      "name": "Offene Rechnungen aus Lexware Office holen",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        240,
        0
      ],
      "disabled": true,
      "parameters": {
        "method": "GET",
        "url": "https://api.lexware.io/v1/voucherlist?voucherType=invoice&voucherStatus=overdue&size=250",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "options": {}
      },
      "notes": "Optional, beim Import ausgeschaltet. Holt überfällige Rechnungen aus Lexware Office (Schnittstelle nur Tarif XL). Nicht von uns ausgeführt."
    },
    {
      "id": "830ac7c2-aacd-411e-aa6d-0934a5b97ab0",
      "name": "Testdaten: 5 Rechnungen",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        240,
        180
      ],
      "parameters": {
        "jsCode": "// Erfundene Rechnungen im Aufbau der Lexware-Belegliste. Fälligkeiten relativ zu heute, damit der Test jeden Tag gleich ausgeht.\n// RE-2026-095 trägt Datum mit Uhrzeit wie in der Lexware-Doku, damit der Test auch dieses Format abdeckt.\nconst tag = (versatz) => new Date(Date.now() + versatz * 86400000).toISOString().slice(0, 10);\nreturn [\n  { content: [\n    { voucherNumber: 'RE-2026-101', voucherDate: tag(-10), dueDate: tag(5), contactName: 'Hoffmann Floristik', totalAmount: 345.1, openAmount: 345.1, currency: 'EUR', voucherStatus: 'open' },\n    { voucherNumber: 'RE-2026-095', voucherDate: tag(-17) + 'T00:00:00.000+01:00', dueDate: tag(-3) + 'T00:00:00.000+01:00', contactName: 'Wolf & Partner', totalAmount: 321.3, openAmount: 321.3, currency: 'EUR', voucherStatus: 'overdue' },\n    { voucherNumber: 'RE-2026-088', voucherDate: tag(-30), dueDate: tag(-16), contactName: 'Becker Bau', totalAmount: 1190, openAmount: 1190, currency: 'EUR', voucherStatus: 'overdue' },\n    { voucherNumber: 'RE-2026-071', voucherDate: tag(-54), dueDate: tag(-40), contactName: 'Klein Design', totalAmount: 595, openAmount: 595, currency: 'EUR', voucherStatus: 'overdue' },\n    { voucherNumber: 'RE-2026-090', voucherDate: tag(-25), dueDate: tag(-11), contactName: 'Muster GmbH', totalAmount: 238, openAmount: 0, currency: 'EUR', voucherStatus: 'paid' },\n  ] },\n].map((j) => ({ json: j }));\n"
      },
      "notes": "Fünf erfundene Rechnungen: eine noch nicht fällig, drei überfällig, eine bezahlt. Eine trägt das Datum mit Uhrzeit, wie Lexware es liefert."
    },
    {
      "id": "5653214a-a58d-440d-a60a-dbcf7ccd42d1",
      "name": "Rechnungen einzeln",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        80
      ],
      "parameters": {
        "jsCode": "// Die Belegliste kommt als ein Paket mit einer Liste \"content\": hier wird jede Rechnung ein eigener Eintrag.\nconst ergebnis = [];\nfor (const item of $input.all()) {\n  for (const r of item.json.content ?? []) ergebnis.push({ json: r });\n}\nreturn ergebnis;\n"
      },
      "notes": "Macht aus der Liste einzelne Rechnungen. Ist der Lexware-Schritt ausgeschaltet, kommt hier im echten Betrieb nichts an."
    },
    {
      "id": "26ee6b20-d735-4a39-add1-05dfe100b68b",
      "name": "Überfälligkeit prüfen",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        80
      ],
      "parameters": {
        "jsCode": "// ===== Deine Angaben =====\nconst AB_TAG_ERINNERUNG = 1; // Tage nach Fälligkeit: freundliche Erinnerung\nconst AB_TAG_MAHNUNG = 14; // Tage nach Fälligkeit: Mahnung\nconst AB_TAG_SELBST = 28; // Tage nach Fälligkeit: nicht mehr automatisch, du entscheidest\nconst ZAHLUNGSZIEL_TAGE = 7; // neue Frist im Text\n// ==========================\nconst euro = (z) => Number(z).toLocaleString('de-DE', { style: 'currency', currency: 'EUR' });\n// Lexware liefert Datum mit Uhrzeit (2026-11-06T00:00:00.000+01:00): nur die ersten 10 Zeichen zählen.\nconst nurTag = (iso) => String(iso ?? '').slice(0, 10);\nconst datum = (iso) => nurTag(iso).split('-').reverse().join('.');\nconst heute = new Date(new Date().toISOString().slice(0, 10));\nreturn $input.all().map(({ json: r }) => {\n  const offen = Number(r.openAmount ?? 0);\n  const tage = Math.floor((heute - new Date(nurTag(r.dueDate))) / 86400000);\n  let stufe = 'nicht fällig';\n  if (offen > 0 && tage >= AB_TAG_SELBST) stufe = 'Selbst entscheiden';\n  else if (offen > 0 && tage >= AB_TAG_MAHNUNG) stufe = 'Mahnung';\n  else if (offen > 0 && tage >= AB_TAG_ERINNERUNG) stufe = 'Erinnerung';\n  // openAmount ist laut Lexware der offene Betrag, bei Teilzahlung also nicht der Rechnungsbetrag\n  const kopf = `Rechnung ${r.voucherNumber} vom ${datum(r.voucherDate)}, fällig am ${datum(r.dueDate)}`;\n  const betrag = `Offener Betrag: ${euro(offen)}.`;\n  const texte = {\n    Erinnerung: {\n      betreff: `Zahlungserinnerung zu Rechnung ${r.voucherNumber}`,\n      text: `Guten Tag,\\n\\nsicher ist es nur durchgerutscht: Unsere ${kopf}, ist noch offen. ${betrag} Bitte überweisen Sie den Betrag in den nächsten ${ZAHLUNGSZIEL_TAGE} Tagen.\\n\\nHaben Sie schon bezahlt? Dann betrachten Sie diese Nachricht bitte als gegenstandslos.\\n\\nViele Grüße`,\n    },\n    Mahnung: {\n      betreff: `Mahnung zu Rechnung ${r.voucherNumber}`,\n      text: `Guten Tag,\\n\\nunsere ${kopf}, ist seit ${tage} Tagen überfällig. ${betrag} Wir bitten Sie, den offenen Betrag innerhalb von ${ZAHLUNGSZIEL_TAGE} Tagen zu überweisen.\\n\\nFalls es ein Problem mit der Rechnung gibt, melden Sie sich bitte kurz.\\n\\nViele Grüße`,\n    },\n    'Selbst entscheiden': {\n      betreff: `Seit ${tage} Tagen überfällig: Rechnung ${r.voucherNumber} (${r.contactName})`,\n      text: `${kopf}. ${betrag} Seit ${tage} Tagen überfällig. Die Stufen für Erinnerung und Mahnung sind verstrichen. Wie es weitergeht (Anruf, Mahnbescheid, Inkasso), entscheidest du.`,\n    },\n  };\n  return { json: { nummer: r.voucherNumber, kunde: r.contactName, offen, faellig: nurTag(r.dueDate), tageUeberfaellig: tage, stufe, ...(texte[stufe] ?? {}) } };\n});\n"
      },
      "notes": "Rechnet die Tage seit Fälligkeit und wählt die Stufe: Erinnerung, Mahnung oder selbst entscheiden. Schreibt den passenden Text."
    },
    {
      "id": "15714dc7-2040-42ba-a7ba-bfe99fc3ccab",
      "name": "Nach Stufe verteilen",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        960,
        80
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "99c2b368-db27-4515-a03e-4aadb1c21b2f",
                    "leftValue": "={{ $json.stufe }}",
                    "rightValue": "Erinnerung",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Erinnerung"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "de00c6fe-dab7-424c-a0ba-1a046771cefc",
                    "leftValue": "={{ $json.stufe }}",
                    "rightValue": "Mahnung",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Mahnung"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "bb123da5-81e5-485f-a974-5b3d9a519d0e",
                    "leftValue": "={{ $json.stufe }}",
                    "rightValue": "Selbst entscheiden",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Selbst entscheiden"
            }
          ]
        },
        "looseTypeValidation": true,
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Noch nicht fällig"
        }
      },
      "notes": "Jede Rechnung geht in den Zweig ihrer Stufe."
    },
    {
      "id": "adedc122-7f16-439a-a64d-42cd54e12322",
      "name": "Entwurf an dich: Erinnerung",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        1240,
        -120
      ],
      "disabled": true,
      "parameters": {
        "fromEmail": "Ablauf <deine-adresse@example.com>",
        "toEmail": "deine-adresse@example.com",
        "subject": "={{ 'Entwurf für ' + $json.kunde + ': ' + $json.betreff }}",
        "emailFormat": "text",
        "text": "={{ $json.text }}",
        "options": {
          "appendAttribution": false
        }
      },
      "notes": "Schickt dir den Entwurf. Du prüfst und leitest ihn an den Kunden weiter. Beim Import ausgeschaltet."
    },
    {
      "id": "cea0c8be-828a-405f-a96c-4697ed6757a0",
      "name": "Entwurf an dich: Mahnung",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        1240,
        40
      ],
      "disabled": true,
      "parameters": {
        "fromEmail": "Ablauf <deine-adresse@example.com>",
        "toEmail": "deine-adresse@example.com",
        "subject": "={{ 'Entwurf für ' + $json.kunde + ': ' + $json.betreff }}",
        "emailFormat": "text",
        "text": "={{ $json.text }}",
        "options": {
          "appendAttribution": false
        }
      },
      "notes": "Schickt dir den Mahnungs-Entwurf. Beim Import ausgeschaltet."
    },
    {
      "id": "a9015c65-a8b9-4c94-a5df-b2a5787758b4",
      "name": "Hinweis an dich: selbst entscheiden",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        1240,
        200
      ],
      "disabled": true,
      "parameters": {
        "fromEmail": "Ablauf <deine-adresse@example.com>",
        "toEmail": "deine-adresse@example.com",
        "subject": "={{ $json.betreff }}",
        "emailFormat": "text",
        "text": "={{ $json.text }}",
        "options": {
          "appendAttribution": false
        }
      },
      "notes": "Sagt dir, welche Rechnung lange offen ist. Beim Import ausgeschaltet."
    },
    {
      "id": "fea3c4ad-1aae-4689-a398-738473243916",
      "name": "Noch nicht fällig: nichts tun",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1240,
        360
      ],
      "parameters": {},
      "notes": "Nicht fällige und bezahlte Rechnungen bleiben unberührt."
    }
  ],
  "connections": {
    "Test: Start per Klick": {
      "main": [
        [
          {
            "node": "Testdaten: 5 Rechnungen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Jeden Montag um 8 Uhr": {
      "main": [
        [
          {
            "node": "Offene Rechnungen aus Lexware Office holen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Offene Rechnungen aus Lexware Office holen": {
      "main": [
        [
          {
            "node": "Rechnungen einzeln",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Testdaten: 5 Rechnungen": {
      "main": [
        [
          {
            "node": "Rechnungen einzeln",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rechnungen einzeln": {
      "main": [
        [
          {
            "node": "Überfälligkeit prüfen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Überfälligkeit prüfen": {
      "main": [
        [
          {
            "node": "Nach Stufe verteilen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Nach Stufe verteilen": {
      "main": [
        [
          {
            "node": "Entwurf an dich: Erinnerung",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Entwurf an dich: Mahnung",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Hinweis an dich: selbst entscheiden",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Noch nicht fällig: nichts tun",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "Europe/Berlin"
  },
  "pinData": {}
}
