{
  "name": "Angebote automatisch nachfassen",
  "nodes": [
    {
      "id": "c751168d-cd26-4b06-a7f0-d224859b0626",
      "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 Angebote laufen durch, nichts wird gesendet.\n2. In **Wer ist dran?** oben die Abstände und Texte anpassen.\n3. Echte Angebote: **Offene Angebote aus Lexware Office holen** mit API-Schlüssel (Tarif XL, Zugang \"Bearer Auth\") einrichten und einschalten. Ohne Lexware: deine Angebotsliste in denselben Aufbau bringen wie die Testdaten.\n4. Die E-Mail-Knoten einrichten und einschalten. Die Entwürfe gehen **an dich**, du schickst sie selbst weiter.\n5. Der Zeitplan läuft einmal pro Woche: So kommt jedes Angebot höchstens einmal pro Stufe.",
        "height": 320,
        "width": 560,
        "color": 4
      }
    },
    {
      "id": "f8cdf21b-7cb4-437b-a047-ebf54fb0518e",
      "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": "2b05a30b-ad79-40ff-ae36-b985f8ff75db",
      "name": "Jeden Montag um 9 Uhr",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "weeksInterval": 1,
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "notes": "Startet einmal pro Woche."
    },
    {
      "id": "2365d4e4-ad0e-4ac6-a423-6a25ccdcfcf9",
      "name": "Offene Angebote 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=quotation&voucherStatus=open&size=250",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "options": {}
      },
      "notes": "Optional, beim Import ausgeschaltet. Holt offene Angebote aus Lexware Office (Schnittstelle nur Tarif XL). Nicht von uns ausgeführt."
    },
    {
      "id": "c6f5868f-9db6-4382-ae44-5d679ab8fd52",
      "name": "Testdaten: 5 Angebote",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        240,
        180
      ],
      "parameters": {
        "jsCode": "// Erfundene Angebote im Aufbau der Lexware-Belegliste. Datum relativ zu heute, damit der Test jeden Tag gleich ausgeht.\nconst tag = (versatz) => new Date(Date.now() + versatz * 86400000).toISOString().slice(0, 10);\nreturn [\n  { json: { content: [\n    { voucherNumber: 'AN-2026-031', voucherDate: tag(-3), contactName: 'Hoffmann Floristik', totalAmount: 345.1, voucherStatus: 'open' },\n    { voucherNumber: 'AN-2026-027', voucherDate: tag(-9), contactName: 'Wolf & Partner', totalAmount: 321.3, voucherStatus: 'open' },\n    { voucherNumber: 'AN-2026-022', voucherDate: tag(-16) + 'T00:00:00.000+01:00', contactName: 'Becker Bau', totalAmount: 1428, voucherStatus: 'open' },\n    { voucherNumber: 'AN-2026-015', voucherDate: tag(-25), contactName: 'Klein Design', totalAmount: 773.5, voucherStatus: 'open' },\n    { voucherNumber: 'AN-2026-019', voucherDate: tag(-12), contactName: 'Muster GmbH', totalAmount: 595, voucherStatus: 'accepted' },\n  ] } },\n];\n"
      },
      "notes": "Fünf erfundene Angebote: unterschiedlich alt, eines schon angenommen."
    },
    {
      "id": "011ff599-2317-4ab4-abe7-2451cfb40a04",
      "name": "Angebote einzeln",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        80
      ],
      "parameters": {
        "jsCode": "const ergebnis = [];\nfor (const item of $input.all()) for (const v of item.json.content ?? []) ergebnis.push({ json: v });\nreturn ergebnis;\n"
      },
      "notes": "Macht aus der Liste einzelne Angebote."
    },
    {
      "id": "1b85b521-e10a-47f1-a975-e72ed9eb36e7",
      "name": "Wer ist dran?",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        80
      ],
      "parameters": {
        "jsCode": "// ===== Deine Angaben =====\nconst ERSTES_NACHFASSEN_AB_TAG = 7;\nconst ZWEITES_NACHFASSEN_AB_TAG = 14;\nconst ANRUFEN_AB_TAG = 21;\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: v }) => {\n  const tage = Math.floor((heute - new Date(nurTag(v.voucherDate))) / 86400000);\n  const offen = v.voucherStatus === 'open';\n  let stufe = 'noch warten';\n  // Jede Stufe gilt 7 Tage lang: Bei wöchentlichem Lauf kommt jedes Angebot genau einmal pro Stufe dran.\n  if (!offen) stufe = 'erledigt';\n  else if (tage >= ANRUFEN_AB_TAG && tage < ANRUFEN_AB_TAG + 7) stufe = 'Anrufen';\n  else if (tage >= ZWEITES_NACHFASSEN_AB_TAG && tage < ZWEITES_NACHFASSEN_AB_TAG + 7) stufe = '2. Nachfassen';\n  else if (tage >= ERSTES_NACHFASSEN_AB_TAG && tage < ERSTES_NACHFASSEN_AB_TAG + 7) stufe = '1. Nachfassen';\n  const kopf = `unser Angebot ${v.voucherNumber} vom ${datum(v.voucherDate)} über ${euro(v.totalAmount)}`;\n  const texte = {\n    '1. Nachfassen': { betreff: `Kurze Nachfrage zu Angebot ${v.voucherNumber}`, text: `Guten Tag,\\n\\nich wollte kurz nachfragen, ob ${kopf} angekommen ist und ob Sie noch Fragen dazu haben. Gern passe ich es an.\\n\\nViele Grüße` },\n    '2. Nachfassen': { betreff: `Angebot ${v.voucherNumber}: noch aktuell für Sie?`, text: `Guten Tag,\\n\\n${kopf} ist noch offen. Ist das Thema für Sie noch aktuell? Eine kurze Antwort genügt, dann weiß ich, woran ich bin.\\n\\nViele Grüße` },\n    Anrufen: { betreff: `Anrufen: ${v.contactName}, Angebot ${v.voucherNumber}`, text: `Seit ${tage} Tagen offen: ${kopf}. Die Stufen für die erste und zweite Nachfrage sind verstrichen. Ein kurzer Anruf klärt es meist schneller.` },\n  };\n  return { json: { nummer: v.voucherNumber, kunde: v.contactName, tageSeitAngebot: tage, stufe, ...(texte[stufe] ?? {}) } };\n});\n"
      },
      "notes": "Rechnet das Alter jedes Angebots und wählt die Stufe: 1. Nachfassen, 2. Nachfassen, anrufen oder noch warten."
    },
    {
      "id": "8337ba9a-0ba9-4044-ad7d-e2d03f1f938c",
      "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": "54947a98-b37e-4708-a68a-9ecf8e9cd089",
                    "leftValue": "={{ $json.stufe }}",
                    "rightValue": "1. Nachfassen",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "1. Nachfassen"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "6e2e7ab7-509b-4f45-ae70-3e10c3ac5bab",
                    "leftValue": "={{ $json.stufe }}",
                    "rightValue": "2. Nachfassen",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "2. Nachfassen"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "a90bff09-737c-4cea-ae3a-8007d20967b4",
                    "leftValue": "={{ $json.stufe }}",
                    "rightValue": "Anrufen",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Anrufen"
            }
          ]
        },
        "looseTypeValidation": true,
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Noch nicht dran"
        }
      },
      "notes": "Jedes Angebot geht in den Zweig seiner Stufe."
    },
    {
      "id": "5d1d54cd-599b-47af-a56f-dcd56f8e399f",
      "name": "Entwurf an dich: 1. Nachfassen",
      "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 zum Weiterleiten. Beim Import ausgeschaltet."
    },
    {
      "id": "bce768dc-5e13-4cdd-ad91-041497ff1a3d",
      "name": "Entwurf an dich: 2. Nachfassen",
      "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 zweiten Entwurf. Beim Import ausgeschaltet."
    },
    {
      "id": "34800ca1-b881-4211-a7d8-695c73f1d806",
      "name": "Erinnerung an dich: anrufen",
      "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": "Erinnert dich an einen Anruf. Beim Import ausgeschaltet."
    },
    {
      "id": "010ebe13-3fbd-4c2e-ac5b-b3065f0a3350",
      "name": "Noch nicht dran: nichts tun",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1240,
        360
      ],
      "parameters": {},
      "notes": "Junge, angenommene oder abgelehnte Angebote bleiben unberührt."
    }
  ],
  "connections": {
    "Test: Start per Klick": {
      "main": [
        [
          {
            "node": "Testdaten: 5 Angebote",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Jeden Montag um 9 Uhr": {
      "main": [
        [
          {
            "node": "Offene Angebote aus Lexware Office holen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Offene Angebote aus Lexware Office holen": {
      "main": [
        [
          {
            "node": "Angebote einzeln",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Testdaten: 5 Angebote": {
      "main": [
        [
          {
            "node": "Angebote einzeln",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Angebote einzeln": {
      "main": [
        [
          {
            "node": "Wer ist dran?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wer ist dran?": {
      "main": [
        [
          {
            "node": "Nach Stufe verteilen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Nach Stufe verteilen": {
      "main": [
        [
          {
            "node": "Entwurf an dich: 1. Nachfassen",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Entwurf an dich: 2. Nachfassen",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Erinnerung an dich: anrufen",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Noch nicht dran: nichts tun",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "Europe/Berlin"
  },
  "pinData": {}
}
