Kündigung und Widerruf: Paketzahl in jeder Bestätigung, klare Hinweise fürs Team, Tests
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
e5cc2f3c82
commit
0d2254ca20
6 files changed
+275
-39
No files matched your search
@@ -7,8 +7,8 @@
|
||||
Betreff: Eingangsbestätigung Ihrer Kündigung – WEBklar Wartungs-Abo
|
||||
Absender: „WEBklar“ <Portal-Postfach>
|
||||
Empfänger: E-Mail aus dem Formular · BCC intern
|
||||
Platzhalter: {{name}}, {{kuendigungsart}}, {{eingang_zeitpunkt}}, {{email}}, {{kundennummer}}, {{vertrag}}, {{wunschtermin}}, {{grund}}, {{vertragsende}}, {{pakete}}, {{pakete_neu}}
|
||||
Optionale Blöcke (zwischen WENN-/ENDE-Kommentaren; bei Nichtzutreffen samt Inhalt entfernen): kundennummer, grund, automatisch_gekuendigt, sonderkuendigung, ausserordentlich, kein_abo_gefunden, zusatzspeicher, pruefen, abo
|
||||
Platzhalter: {{name}}, {{kuendigungsart}}, {{eingang_zeitpunkt}}, {{email}}, {{kundennummer}}, {{vertrag}}, {{wunschtermin}}, {{grund}}, {{vertragsende}}, {{pakete}}, {{pakete_neu}}, {{pakete_angabe}}
|
||||
Optionale Blöcke (zwischen WENN-/ENDE-Kommentaren; bei Nichtzutreffen samt Inhalt entfernen): kundennummer, grund, automatisch_gekuendigt, sonderkuendigung, ausserordentlich, kein_abo_gefunden, zusatzspeicher, pruefen, abo, speicher_angaben, speicher_kind_pruefung
|
||||
-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
@@ -39,6 +39,9 @@ a{color:#111111;}
|
||||
<!-- WENN kundennummer -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Kundennummer</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{kundennummer}}</td></tr>
|
||||
<!-- ENDE kundennummer -->
|
||||
<!-- WENN speicher_angaben -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Pakete</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{pakete_angabe}}</td></tr>
|
||||
<!-- ENDE speicher_angaben -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Vertrag</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{vertrag}}</td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Gewünschter Zeitpunkt</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{wunschtermin}}</td></tr>
|
||||
<!-- WENN grund -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;color:#6b6964;">Grund</td><td class="val ink rowline" valign="top" style="padding:12px 0;color:#111111;">{{grund}}</td></tr>
|
||||
@@ -69,6 +72,9 @@ a{color:#111111;}
|
||||
<!-- WENN pruefen -->
|
||||
<tr><td class="px" style="padding:28px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#f7f6f3;border:1px solid #e8e6e0;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Wir prüfen Ihre Kündigung</div><div class="mut" style="color:#4a4843;">Wir prüfen Ihre Kündigung und bestätigen Ihnen den Zeitpunkt, zu dem sie wirkt, gesondert per E-Mail.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE pruefen -->
|
||||
<!-- WENN speicher_kind_pruefung -->
|
||||
<tr><td class="px" style="padding:28px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#f7f6f3;border:1px solid #e8e6e0;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Wir prüfen die Art Ihrer Kündigung</div><div class="mut" style="color:#4a4843;">Ihre {{kuendigungsart}} wird geprüft. Den Zusatzspeicher haben wir unabhängig davon wie oben zum Ende des Abrechnungsmonats verringert; ergibt die Prüfung ein früheres Ende, bestätigen wir es Ihnen gesondert.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE speicher_kind_pruefung -->
|
||||
|
||||
<!-- WENN abo -->
|
||||
<tr><td class="px mut" style="padding:24px 40px 0 40px;font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:25px;mso-line-height-rule:exactly;color:#4a4843;">Ein bestehendes Stundenguthaben verfällt mit Vertragsende. Ihre Daten, den Domain-AuthCode und Ihr Postfach stellen wir Ihnen auf Wunsch gemäß § 9 der Vertragsbedingungen bereit.</td></tr>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
Betreff: [Abo] Kündigung eingegangen: {{email}}
|
||||
Absender: „WEBklar Kundenportal“ <Portal-Postfach>
|
||||
Empfänger: kenso@webklar.com, andrej@webklar.com
|
||||
Platzhalter: {{email}}, {{name}}, {{kundennummer}}, {{vertrag}}, {{kuendigungsart}}, {{wunschtermin}}, {{grund}}, {{vertragsende}}, {{stripe_abo_id}}, {{pakete}}, {{fehler}}
|
||||
Optionale Blöcke (zwischen WENN-/ENDE-Kommentaren; bei Nichtzutreffen samt Inhalt entfernen): kundennummer, grund, automatisch_gekuendigt, sonderkuendigung, ausserordentlich, kein_abo_gefunden, zusatzspeicher, kein_speicher, wechsel_ausstehend, speicher_fehlgeschlagen, nachweis_fehlt
|
||||
Platzhalter: {{email}}, {{name}}, {{kundennummer}}, {{vertrag}}, {{kuendigungsart}}, {{wunschtermin}}, {{grund}}, {{vertragsende}}, {{stripe_abo_id}}, {{pakete}}, {{pakete_angabe}}, {{fehler}}
|
||||
Optionale Blöcke (zwischen WENN-/ENDE-Kommentaren; bei Nichtzutreffen samt Inhalt entfernen): kundennummer, grund, automatisch_gekuendigt, sonderkuendigung, ausserordentlich, kein_abo_gefunden, zusatzspeicher, kein_speicher, wechsel_ausstehend, speicher_fehlgeschlagen, nachweis_fehlt, speicher_angaben, speicher_kind_pruefung
|
||||
-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
@@ -38,6 +38,9 @@ a{color:#111111;}
|
||||
<!-- WENN kundennummer -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Kundennummer</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{kundennummer}}</td></tr>
|
||||
<!-- ENDE kundennummer -->
|
||||
<!-- WENN speicher_angaben -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Pakete</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{pakete_angabe}}</td></tr>
|
||||
<!-- ENDE speicher_angaben -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Vertrag</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{vertrag}}</td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Art</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{kuendigungsart}}</td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Gewünschter Zeitpunkt</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{wunschtermin}}</td></tr>
|
||||
<!-- WENN grund -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;color:#6b6964;">Grund</td><td class="val ink rowline" valign="top" style="padding:12px 0;color:#111111;">{{grund}}</td></tr>
|
||||
@@ -69,14 +72,17 @@ a{color:#111111;}
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Achtung</div><div class="mut" style="color:#4a4843;">Abo {{stripe_abo_id}} gefunden, aber kein Zusatzspeicher gebucht. Bei Stripe ist nichts zu tun; der Kunde hat „wir prüfen“ bekommen – bitte kurz antworten.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE kein_speicher -->
|
||||
<!-- WENN wechsel_ausstehend -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Zu tun</div><div class="mut" style="color:#4a4843;">Wechsel ausstehend – Speicher nach Abschluss des Wechsels von Hand reduzieren ({{stripe_abo_id}}, gekündigt: {{pakete}} Paket(e)). Solange die Wechselzahlung aussteht, würde eine Änderung des Abos die Wechselrechnung stornieren. Der Kunde hat „wir prüfen“ bekommen; den Zeitpunkt bestätigen.</div></td></tr></table></td></tr>
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Zu tun</div><div class="mut" style="color:#4a4843;">Wechsel ausstehend – Speicher nach Abschluss des Wechsels von Hand reduzieren ({{stripe_abo_id}}, gekündigt: {{pakete_angabe}}). Solange die Wechselzahlung aussteht, würde eine Änderung des Abos die Wechselrechnung stornieren. Der Kunde hat „wir prüfen“ bekommen; den Zeitpunkt bestätigen.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE wechsel_ausstehend -->
|
||||
<!-- WENN speicher_fehlgeschlagen -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Achtung</div><div class="mut" style="color:#4a4843;">Zusatzspeicher NICHT automatisch verringert ({{stripe_abo_id}}, gekündigt: {{pakete}} Paket(e)): {{fehler}} Bitte in Stripe von Hand verringern und dem Kunden den Zeitpunkt bestätigen.</div></td></tr></table></td></tr>
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Achtung</div><div class="mut" style="color:#4a4843;">Zusatzspeicher NICHT automatisch verringert ({{stripe_abo_id}}, gekündigt: {{pakete_angabe}}): {{fehler}} Bitte in Stripe von Hand verringern und dem Kunden den Zeitpunkt bestätigen.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE speicher_fehlgeschlagen -->
|
||||
<!-- WENN nachweis_fehlt -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Nachweis nicht gespeichert</div><div class="mut" style="color:#4a4843;">Das Ereignis kuendigung konnte nicht in contractEvents angelegt werden. Diese Mail ist der Nachweis der Erklärung.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE nachweis_fehlt -->
|
||||
<!-- WENN speicher_kind_pruefung -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Zu tun</div><div class="mut" style="color:#4a4843;">{{kuendigungsart}} des Zusatzspeichers: Grund prüfen, ggf. früher beenden und den Rest erstatten. Die Verringerung zum Periodenende läuft unabhängig davon (siehe oben).</div></td></tr></table></td></tr>
|
||||
<!-- ENDE speicher_kind_pruefung -->
|
||||
|
||||
<tr><td style="padding:0 0 44px 0;font-size:0;line-height:0;"> </td></tr>
|
||||
</table>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
Betreff: [Abo] WIDERRUF eingegangen: {{email}}
|
||||
Absender: „WEBklar Kundenportal“ <Portal-Postfach>
|
||||
Empfänger: kenso@webklar.com, andrej@webklar.com
|
||||
Platzhalter: {{email}}, {{name}}, {{kundennummer}}, {{bestellung}}, {{stripe_abo_id}}, {{abo_beginn}}, {{fristende}}, {{rechtzeitig}}, {{ereignisse}}
|
||||
Optionale Blöcke (zwischen WENN-/ENDE-Kommentaren; bei Nichtzutreffen samt Inhalt entfernen): kundennummer, abo_gefunden, auf_kuendigung_gesetzt, kein_abo_gefunden, kuendigung_fehlgeschlagen, abschluss, wechsel, zusatzspeicher, keine_frist, nachweis_fehlt
|
||||
Platzhalter: {{email}}, {{name}}, {{kundennummer}}, {{bestellung}}, {{stripe_abo_id}}, {{abo_beginn}}, {{fristende}}, {{rechtzeitig}}, {{ereignisse}}, {{pruefhinweis}}
|
||||
Optionale Blöcke (zwischen WENN-/ENDE-Kommentaren; bei Nichtzutreffen samt Inhalt entfernen): kundennummer, abo_gefunden, auf_kuendigung_gesetzt, kein_abo_gefunden, kuendigung_fehlgeschlagen, abschluss, wechsel, zusatzspeicher, keine_frist, nachweis_fehlt, wechsel_offen, abschluss_verspaetet, nicht_pruefbar, bereits_widerrufen
|
||||
-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
@@ -39,7 +39,7 @@ a{color:#111111;}
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Kundennummer</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{kundennummer}}</td></tr>
|
||||
<!-- ENDE kundennummer -->
|
||||
<!-- WENN abo_gefunden -->
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Stripe-Abo</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{stripe_abo_id}}<!-- WENN auf_kuendigung_gesetzt --> <span class="mut" style="color:#6b6964;">(auf Kündigung gesetzt)</span><!-- ENDE auf_kuendigung_gesetzt --></td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Abo-Beginn</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{abo_beginn}}</td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Widerrufsfrist bis</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{fristende}}, 24 Uhr</td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;color:#6b6964;">Eingang</td><td class="val ink rowline" valign="top" style="padding:12px 0;color:#111111;"><strong>{{rechtzeitig}}</strong></td></tr>
|
||||
<tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Stripe-Abo</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{stripe_abo_id}}<!-- WENN auf_kuendigung_gesetzt --> <span class="mut" style="color:#6b6964;">(auf Kündigung gesetzt)</span><!-- ENDE auf_kuendigung_gesetzt --></td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Abo-Beginn</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{abo_beginn}}</td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;border-bottom:1px solid #ecebe6;color:#6b6964;">Widerrufsfrist bis</td><td class="val ink rowline" valign="top" style="padding:12px 0;border-bottom:1px solid #ecebe6;color:#111111;">{{fristende}}</td></tr><tr><td class="lbl mut rowline" width="170" valign="top" style="width:170px;padding:12px 12px 12px 0;color:#6b6964;">Eingang</td><td class="val ink rowline" valign="top" style="padding:12px 0;color:#111111;"><strong>{{rechtzeitig}}</strong></td></tr>
|
||||
<!-- ENDE abo_gefunden -->
|
||||
</table></td></tr>
|
||||
|
||||
@@ -63,6 +63,18 @@ a{color:#111111;}
|
||||
<!-- WENN keine_frist -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Achtung</div><div class="mut" style="color:#4a4843;">Nichts automatisch geändert – keine offene Frist gefunden: zu dieser Bestellung läuft keine Widerrufsfrist (mehr) oder es gibt keine Bestellung dieser Art. Bitte prüfen, bevor der Widerruf abgelehnt wird; der Kunde hat „wir prüfen“ bekommen.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE keine_frist -->
|
||||
<!-- WENN wechsel_offen -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Achtung</div><div class="mut" style="color:#4a4843;">Wechselrechnung noch offen – stornieren, damit der Wechsel nicht nachträglich wirksam wird (Stripe → Rechnung stornieren; die zurückgehaltene Änderung verfällt damit).</div></td></tr></table></td></tr>
|
||||
<!-- ENDE wechsel_offen -->
|
||||
<!-- WENN abschluss_verspaetet -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Hinweis</div><div class="mut" style="color:#4a4843;">Widerruf des Abschlusses nach der Frist: ggf. als ordentliche Kündigung behandeln (Mindestlaufzeit beachten) und dem Kunden das Ergebnis mitteilen.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE abschluss_verspaetet -->
|
||||
<!-- WENN nicht_pruefbar -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Achtung</div><div class="mut" style="color:#4a4843;">Widerrufsfrist nur eingeschränkt prüfbar: {{pruefhinweis}}. Beim Abschluss zählt ersatzweise der Abo-Beginn; ohne offene Frist wurde nichts automatisch geändert und der Kunde hat „wir prüfen“ bekommen.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE nicht_pruefbar -->
|
||||
<!-- WENN bereits_widerrufen -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Hinweis</div><div class="mut" style="color:#4a4843;">Diese Bestellung ist schon widerrufen (Ereignis widerrufen). Nichts weiter zu tun, sofern die Rückabwicklung läuft; dem Kunden kurz antworten.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE bereits_widerrufen -->
|
||||
<!-- WENN nachweis_fehlt -->
|
||||
<tr><td class="px" style="padding:24px 40px 0 40px;"><table role="presentation" class="box" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fdf0ef;border:1px solid #f1c9c5;border-radius:12px;"><tr><td class="ink" style="padding:20px 22px;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:21px;color:#111111;"><div class="ink" style="font-weight:bold;color:#111111;padding-bottom:6px;">Nachweis nicht gespeichert</div><div class="mut" style="color:#4a4843;">Das Ereignis widerruf konnte nicht in contractEvents angelegt werden. Diese Mail ist der Nachweis der Erklärung.</div></td></tr></table></td></tr>
|
||||
<!-- ENDE nachweis_fehlt -->
|
||||
|
||||
+71
-19
@@ -645,7 +645,8 @@ const RATE_WINDOW_MS = 60 * 60 * 1000
|
||||
const RATE_MAX = 10
|
||||
const recentRequests = new Map() // ip -> [timestamps]
|
||||
|
||||
function purgeRateLimit(now) {
|
||||
/** Eintraege aelter als eine Stunde (zum Zeitpunkt now) entfernen; laeuft bei jeder Anfrage, exportiert fuer Tests. */
|
||||
export function purgeRateLimit(now = Date.now()) {
|
||||
for (const [ip, list] of recentRequests) {
|
||||
const fresh = list.filter((t) => now - t < RATE_WINDOW_MS)
|
||||
if (fresh.length) recentRequests.set(ip, fresh)
|
||||
@@ -666,10 +667,9 @@ export function resetPublicRateLimit() {
|
||||
recentRequests.clear()
|
||||
}
|
||||
|
||||
/** Nur fuer Tests: Zahl der IP-Adressen, die zum Zeitpunkt now noch gezaehlt wuerden (aendert nichts). */
|
||||
export function publicRateLimitState({ now = Date.now() } = {}) {
|
||||
const ips = [...recentRequests.values()].filter((list) => list.some((t) => now - t < RATE_WINDOW_MS)).length
|
||||
return { ips }
|
||||
/** Nur fuer Tests: Zahl der IP-Adressen, die gerade in der Map stehen. */
|
||||
export function publicRateLimitState() {
|
||||
return { ips: recentRequests.size }
|
||||
}
|
||||
|
||||
// Auswahl im Formular: Vertrag (Kuendigung) und Bestellung (Widerruf), Standard jeweils der erste Wert
|
||||
@@ -892,9 +892,14 @@ router.post('/public/cancel', async (req, res) => {
|
||||
wunschtermin: storage ? 'Ende des Abrechnungsmonats' : d.effective ? fmtDate(`${d.effective}T12:00:00Z`) : 'nächstmöglicher Zeitpunkt',
|
||||
grund: d.reason,
|
||||
vertragsende: fmtDate(effectiveAt),
|
||||
// {{pakete}} = gekuendigte Pakete (F31); solange nichts verringert wurde, der Wunsch des Kunden
|
||||
pakete: reduced ? result.details.packages : d.packages ?? 'alle',
|
||||
// {{pakete}} = tatsaechlich gekuendigte Pakete (F31, nur nach einer Verringerung); {{pakete_angabe}} = die
|
||||
// Erklaerung des Kunden (Inhalt der Erklaerung, § 312k Abs. 4 BGB) in jedem Speicherpfad
|
||||
pakete: reduced ? result.details.packages : '',
|
||||
pakete_angabe: d.packages ? `${d.packages} Paket(e)` : 'alle gebuchten Pakete',
|
||||
}
|
||||
// Eine ausserordentliche Kuendigung oder Geschaeftsaufgabe des Speichers wird trotzdem zum Periodenende
|
||||
// verringert; die Pruefung der Art kommt dazu (Fix 1, 6)
|
||||
const storageKindCheck = storage && d.kind !== 'ordentlich'
|
||||
|
||||
await sendCustomerMail(d.email, {
|
||||
template: 'K03',
|
||||
@@ -910,6 +915,8 @@ router.post('/public/cancel', async (req, res) => {
|
||||
kein_abo_gefunden: storage ? !sub : !effectiveAt && d.kind !== 'ausserordentlich',
|
||||
zusatzspeicher: reduced,
|
||||
pruefen: storage && Boolean(sub) && !reduced,
|
||||
speicher_angaben: storage,
|
||||
speicher_kind_pruefung: storageKindCheck && reduced,
|
||||
},
|
||||
}).catch((e) => console.error('[abo] Kuendigungsbestaetigung fehlgeschlagen:', e.message))
|
||||
|
||||
@@ -934,6 +941,8 @@ router.post('/public/cancel', async (req, res) => {
|
||||
wechsel_ausstehend: result.outcome === 'wechsel_ausstehend',
|
||||
speicher_fehlgeschlagen: result.outcome === 'fehlgeschlagen',
|
||||
nachweis_fehlt: Boolean(sub) && !result.event,
|
||||
speicher_angaben: storage,
|
||||
speicher_kind_pruefung: storageKindCheck,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -952,13 +961,27 @@ const latestUntil = (list) => list.reduce((latest, w) => (!latest || w.until > l
|
||||
*/
|
||||
async function withdrawOrder(sub, d, receivedAt) {
|
||||
const type = ORDER_EVENT_TYPE[d.order]
|
||||
const events = (await listContractEvents(sub.customerId)).filter((e) => e.subscriptionId === sub.$id && e.type === type)
|
||||
// Ereignisse nicht lesbar: nichts automatisch aendern (ausser dem Rueckfall auf startedAt beim Abschluss),
|
||||
// T09 sagt "von Hand pruefen" (Fix 1, 4)
|
||||
let events = []
|
||||
let unreadable = false
|
||||
try {
|
||||
events = (await listContractEvents(sub.customerId)).filter((e) => e.subscriptionId === sub.$id && e.type === type)
|
||||
} catch (err) {
|
||||
unreadable = true
|
||||
console.error(`[abo] Vertragsereignisse für Widerruf (Abo ${sub.$id}) nicht lesbar:`, err.message)
|
||||
}
|
||||
let open = openWithdrawals(events, receivedAt)
|
||||
let deadline = latestUntil(open)
|
||||
if (type === 'abschluss' && !events.length && sub.startedAt) {
|
||||
const { endsAt } = withdrawalDeadline(sub.startedAt)
|
||||
deadline = endsAt
|
||||
if (receivedAt <= endsAt) open = [{ type, eventId: null, until: endsAt }]
|
||||
let startMissing = false
|
||||
if (type === 'abschluss' && !events.length) {
|
||||
if (sub.startedAt) {
|
||||
const { endsAt } = withdrawalDeadline(sub.startedAt)
|
||||
deadline = endsAt
|
||||
if (receivedAt <= endsAt) open = [{ type, eventId: null, until: endsAt }]
|
||||
} else {
|
||||
startMissing = true
|
||||
}
|
||||
}
|
||||
if (!deadline) {
|
||||
// Frist schon vorbei: das spaeteste Fristende der Bestellungen dieses Typs fuer den Hinweis ans Team
|
||||
@@ -992,7 +1015,23 @@ async function withdrawOrder(sub, d, receivedAt) {
|
||||
}
|
||||
}
|
||||
const event = await recordDeclarationEvent(sub, 'widerruf', receivedAt, { order: d.order, eventId: ids[0] ?? null, eventIds: ids, inTime }, 'offen')
|
||||
return { sub, inTime, deadline, withdrawn, canceled, cancelFailed, event }
|
||||
return {
|
||||
sub,
|
||||
inTime,
|
||||
deadline,
|
||||
withdrawn,
|
||||
canceled,
|
||||
cancelFailed,
|
||||
event,
|
||||
unreadable,
|
||||
startMissing,
|
||||
// Dieselbe Bestellung wurde schon widerrufen (Fix 1, 5)
|
||||
alreadyWithdrawn: !inTime && events.some((e) => e.status === 'widerrufen'),
|
||||
// "NACH Fristende" nur, wenn die Frist wirklich vorbei ist
|
||||
late: !inTime && Boolean(deadline) && receivedAt > deadline,
|
||||
// Kartenwechsel, der noch auf die Zahlung wartet: die offene Wechselrechnung muss storniert werden (Fix 1, 7)
|
||||
openSwitchWithdrawn: withdrawn.some((e) => e.type === 'wechsel' && !e.details?.effectiveAt),
|
||||
}
|
||||
}
|
||||
|
||||
/** Zeile je widerrufenem Ereignis fuer T09: ID, Inhalt (Speicher: Menge vorher -> nachher), Bestelldatum. */
|
||||
@@ -1012,7 +1051,7 @@ router.post('/public/withdraw', async (req, res) => {
|
||||
const receivedAt = new Date()
|
||||
|
||||
let sub = null
|
||||
let result = { inTime: false, deadline: null, withdrawn: [], canceled: false, cancelFailed: false, event: null }
|
||||
let result = { inTime: false, deadline: null, withdrawn: [], canceled: false, cancelFailed: false, event: null, unreadable: false, startMissing: false, alreadyWithdrawn: false, late: false, openSwitchWithdrawn: false }
|
||||
try {
|
||||
sub = await findActiveSubscriptionByEmail(d.email)
|
||||
if (sub) {
|
||||
@@ -1023,6 +1062,8 @@ router.post('/public/withdraw', async (req, res) => {
|
||||
console.error('[abo] Widerruf nicht verarbeitbar:', err.message)
|
||||
}
|
||||
const { inTime } = result
|
||||
// Fuer T09: warum sich die Frist nicht pruefen liess
|
||||
const pruefhinweis = result.unreadable ? 'Ereignisse nicht lesbar – bitte von Hand prüfen' : result.startMissing ? 'Abo-Beginn fehlt' : ''
|
||||
|
||||
await sendCustomerMail(d.email, {
|
||||
template: 'K04',
|
||||
@@ -1052,15 +1093,22 @@ router.post('/public/withdraw', async (req, res) => {
|
||||
bestellung: orderLabel(d.order, sub),
|
||||
stripe_abo_id: sub?.stripeSubscriptionId || '',
|
||||
abo_beginn: fmtDate(sub?.startedAt),
|
||||
fristende: fmtDate(result.deadline),
|
||||
fristende: result.deadline ? `${fmtDate(result.deadline)}, 24 Uhr` : 'keine Frist gefunden',
|
||||
rechtzeitig: !sub
|
||||
? 'ungeprüft (kein Abo gefunden)'
|
||||
: inTime
|
||||
? 'RECHTZEITIG'
|
||||
: result.deadline
|
||||
? 'NACH Fristende, vor einer Ablehnung bitte prüfen'
|
||||
: 'ungeprüft (keine Bestellung dieser Art gefunden)',
|
||||
: result.alreadyWithdrawn
|
||||
? 'bereits widerrufen'
|
||||
: pruefhinweis
|
||||
? `ungeprüft (${pruefhinweis})`
|
||||
: result.late
|
||||
? 'NACH Fristende, vor einer Ablehnung bitte prüfen'
|
||||
: result.deadline
|
||||
? 'ungeprüft (keine offene Frist: Bestellung gescheitert)'
|
||||
: 'ungeprüft (keine Bestellung dieser Art gefunden)',
|
||||
ereignisse: describeWithdrawn(result.withdrawn),
|
||||
pruefhinweis,
|
||||
},
|
||||
blocks: {
|
||||
kundennummer: Boolean(d.customerNumber),
|
||||
@@ -1071,8 +1119,12 @@ router.post('/public/withdraw', async (req, res) => {
|
||||
abschluss: inTime && d.order === 'abschluss',
|
||||
wechsel: inTime && d.order === 'wechsel',
|
||||
zusatzspeicher: inTime && d.order === 'zusatzspeicher',
|
||||
keine_frist: Boolean(sub) && !inTime,
|
||||
keine_frist: Boolean(sub) && !inTime && !pruefhinweis && !result.alreadyWithdrawn,
|
||||
nachweis_fehlt: Boolean(sub) && !result.event,
|
||||
wechsel_offen: result.openSwitchWithdrawn,
|
||||
abschluss_verspaetet: Boolean(sub) && d.order === 'abschluss' && result.late && !result.alreadyWithdrawn,
|
||||
nicht_pruefbar: Boolean(sub) && Boolean(pruefhinweis),
|
||||
bereits_widerrufen: Boolean(sub) && result.alreadyWithdrawn,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
Reference in new issue
Block a user