Terminplaner: G01 Block bestaetigen, G02 kein_widerruf, G06 grund/nachricht, Hinweise zu Blockpaaren

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-03 08:17:43 +00:00
1 parent 274192e88e
commit 6c25a76e28
5 files changed
+69 -24

No files matched your search

+42 -11
View File
@@ -590,12 +590,12 @@ test('G01 und G08 enthalten keinen vom Gast eingegebenen Text (kein Platzhalter
test('G-Vorlagen: Platzhalter und Blöcke wie im Plan', () => {
const common = ['betreff', 'farbe', 'betrieb_name', 'betrieb_adresse', 'betrieb_telefon', 'betrieb_email', 'impressum_url', 'datenschutz_url']
const expected = {
G01: { p: ['leistung', 'datum', 'zeit', 'link'], b: ['zu_viele'] },
G02: { p: ['gast_name', 'leistung', 'person', 'datum', 'zeit', 'dauer', 'preis', 'zahlung', 'nummer', 'link', 'ort', 'storno_text', 'widerrufsbelehrung', 'widerruf_link'], b: ['preis', 'person', 'storno', 'widerruf', 'anfrage_angenommen'] },
G01: { p: ['leistung', 'datum', 'zeit', 'link'], b: ['bestaetigen', 'zu_viele'] },
G02: { p: ['gast_name', 'leistung', 'person', 'datum', 'zeit', 'dauer', 'preis', 'zahlung', 'nummer', 'link', 'ort', 'storno_text', 'widerrufsbelehrung', 'widerruf_link'], b: ['preis', 'person', 'storno', 'widerruf', 'kein_widerruf', 'anfrage_angenommen'] },
G03: { p: ['gast_name', 'leistung', 'datum', 'zeit', 'link'], b: [] },
G04: { p: ['gast_name', 'leistung', 'datum', 'zeit', 'nachricht'], b: ['nachricht'] },
G05: { p: ['gast_name', 'leistung', 'person', 'datum', 'zeit', 'link'], b: ['person'] },
G06: { p: ['gast_name', 'leistung', 'datum', 'zeit', 'absage_von', 'grund'], b: ['nachricht'] },
G06: { p: ['gast_name', 'leistung', 'datum', 'zeit', 'absage_von', 'grund', 'nachricht'], b: ['grund', 'nachricht'] },
G07: { p: ['gast_name', 'leistung', 'alt_datum', 'alt_zeit', 'datum', 'zeit', 'link'], b: [] },
G08: { p: ['eingang', 'nummer'], b: ['zugeordnet', 'nach_frist'] },
}
@@ -606,22 +606,32 @@ test('G-Vorlagen: Platzhalter und Blöcke wie im Plan', () => {
}
})
test('G01: Knopf zur Bestätigung, Hinweis für Dritte; Block zu_viele nennt Telefon und Absagen', () => {
test('G01: Block bestaetigen mit Angaben und Knopf, Block zu_viele nur mit eigenem Text und ohne Knopf', () => {
const tpl = loadTemplate('G01')
const values = { ...sampleValues(tpl), betrieb_name: 'Salon Muster', betrieb_telefon: '06301 1234', leistung: 'Herrenschnitt', datum: 'Montag, 12.10.2026', zeit: '10:00', link: 'https://project.webklar.com/termin.html#v=abc' }
const sie = renderMail('G01', values, { sie: true })
const sie = renderMail('G01', values, { sie: true, bestaetigen: true })
assert.deepEqual(sie.problems, [])
assert.match(sie.text, /Leistung: Herrenschnitt/)
assert.match(sie.text, /Datum: Montag, 12\.10\.2026/)
assert.match(sie.text, /Uhrzeit: 10:00 Uhr/)
assert.match(sie.text, /Termin bestätigen: https:\/\/project\.webklar\.com\/termin\.html#v=abc/)
assert.match(sie.text, /Das waren Sie nicht\? Dann ignorieren Sie diese E-Mail\./)
assert.doesNotMatch(sie.text, /höchstmögliche Zahl/)
assert.doesNotMatch(sie.text, /höchstmögliche Zahl|rufen Sie uns an/)
assert.match(renderMail('G01', values, { du: true, bestaetigen: true }).text, /Das warst du nicht\? Dann ignoriere diese E-Mail\./)
// zu_viele: nichts reserviert, also weder Terminangaben noch Knopf noch Link
const viele = renderMail('G01', values, { sie: true, zu_viele: true })
assert.deepEqual(viele.problems, [])
assert.match(viele.text, /bereits die höchstmögliche Zahl offener Termine/)
assert.match(viele.text, /sagen Sie einen Ihrer offenen Termine ab/)
assert.match(viele.text, /rufen Sie uns an: 06301 1234/)
assert.match(renderMail('G01', values, { du: true }).text, /Das warst du nicht\? Dann ignoriere diese E-Mail\./)
assert.match(viele.text, /rufen Sie uns an: 06301 1234\./)
assert.doesNotMatch(viele.text, /Herrenschnitt|12\.10\.2026|Uhrzeit|Termin bestätigen|termin\.html|ignorieren Sie den Knopf|Knopf/)
assert.doesNotMatch(viele.html, /termin\.html|Herrenschnitt/)
assert.match(renderMail('G01', values, { du: true, zu_viele: true }).text, /ruf uns an: 06301 1234\./)
// ohne gesetzten Block bleibt nur der gemeinsame Rahmen
const leer = renderMail('G01', values, { sie: true })
assert.doesNotMatch(leer.text, /Herrenschnitt|höchstmögliche Zahl|Termin bestätigen/)
})
test('G02: Zusammenfassung, Verwaltungslink, Preis, Person, Storno und Widerruf nur mit ihren Blöcken', () => {
@@ -653,9 +663,20 @@ test('G02: Zusammenfassung, Verwaltungslink, Preis, Person, Storno und Widerruf
// Belehrung wörtlich, Zeilenumbrüche bleiben, Sonderzeichen sind maskiert
assert.match(voll.html, /Widerrufsrecht: 14 Tage &lt;b&gt;ohne&lt;\/b&gt; Gründe\.<br>Zweite Zeile &amp; mehr/)
assert.ok(voll.text.includes('Widerrufsbelehrung\n\nWiderrufsrecht: 14 Tage <b>ohne</b> Gründe.\nZweite Zeile & mehr'), voll.text)
assert.doesNotMatch(voll.text, /kein Widerrufsrecht/, 'widerruf und kein_widerruf schließen sich aus')
// der Wortlaut der Belehrung steht in einem abgesetzten Kasten
assert.match(voll.html, /class="box"[^>]*><tr><td[^>]*>Widerrufsbelehrung<br><br>Widerrufsrecht/)
// Freizeitausnahme: Hinweis statt Widerrufsrecht
const kein = renderMail('G02', values, { sie: true, kein_widerruf: true })
assert.deepEqual(kein.problems, [])
assert.ok(kein.text.includes('Für diese Buchung besteht kein Widerrufsrecht (§ 312g Abs. 2 Nr. 9 BGB). Absagen richten sich nach den Stornobedingungen.'), kein.text)
assert.doesNotMatch(kein.text, /Vertrag widerrufen|Widerrufsbelehrung|Muster-Widerrufsformular/)
const keinDu = renderMail('G02', values, { du: true, kein_widerruf: true })
assert.ok(keinDu.text.includes('Für diese Buchung besteht kein Widerrufsrecht (§ 312g Abs. 2 Nr. 9 BGB). Absagen richten sich nach den Stornobedingungen.'), keinDu.text)
assert.doesNotMatch(keinDu.text, SIE_FORM)
assert.doesNotMatch(basis.text, /kein Widerrufsrecht/)
const du = renderMail('G02', values, { du: true, anfrage_angenommen: true, widerruf: true })
assert.match(du.text, /Dein Termin ist bestätigt/)
assert.match(du.text, /hat deine Terminanfrage angenommen/)
@@ -681,10 +702,20 @@ test('G03, G04, G05, G06, G07: Inhalt je Mail', () => {
assert.doesNotMatch(renderMail('G05', { ...sampleValues(t05), person: 'Anna' }, { du: true }).text, /Anna/)
const t06 = loadTemplate('G06')
const g06 = renderMail('G06', { ...sampleValues(t06), absage_von: 'dem Betrieb', grund: 'Krankheit im Team' }, { sie: true })
const werte06 = { ...sampleValues(t06), absage_von: 'dem Betrieb', grund: 'Krankheit im Team', nachricht: 'Wir melden uns wegen eines neuen Termins.' }
const g06 = renderMail('G06', werte06, { sie: true })
assert.match(g06.text, /Abgesagt von: dem Betrieb/)
assert.doesNotMatch(g06.text, /Krankheit/)
assert.match(renderMail('G06', { ...sampleValues(t06), grund: 'Krankheit im Team' }, { sie: true, nachricht: true }).text, /Krankheit im Team/)
assert.doesNotMatch(g06.text, /Krankheit|Grund:|neuen Termins/)
const g06grund = renderMail('G06', werte06, { sie: true, grund: true })
assert.match(g06grund.text, /Grund: Krankheit im Team/)
assert.doesNotMatch(g06grund.text, /neuen Termins/)
const g06nachricht = renderMail('G06', werte06, { sie: true, nachricht: true })
assert.match(g06nachricht.text, /Nachricht von Wert-betrieb_name\s+Wir melden uns wegen eines neuen Termins\./)
assert.doesNotMatch(g06nachricht.text, /Krankheit/)
const beide = renderMail('G06', werte06, { sie: true, grund: true, nachricht: true })
assert.deepEqual(beide.problems, [])
assert.match(beide.text, /Krankheit im Team/)
assert.match(beide.text, /neuen Termins/)
const t07 = loadTemplate('G07')
const g07 = renderMail('G07', { ...sampleValues(t07), alt_datum: '12.10.2026', alt_zeit: '10:00', datum: '13.10.2026', zeit: '11:30' }, { du: true })