Öffnungszeiten: Behalten nur ohne Abo anbieten (kein_abo)

Behalten (30 €) gab es bei jedem inklusive false. nicht_aktiv und gekuendigt heißen aber,
dass das Wartungs-Abo läuft (Server: 409 Abo läuft wieder). Jetzt gilt an allen fünf Stellen
(Kachel, Karte, Behalten-Seite, Weg aus der Kachel, Abgeschaltet-Karte) dasselbe Prädikat:
inklusive false UND grund kein_abo; sonst „Abo läuft wieder“ ohne Bezahlknopf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-05 05:41:24 +00:00
1 parent 7bb918390a
commit cee44d6852
5 files changed
+166 -20

No files matched your search

+28 -8
View File
@@ -47,6 +47,19 @@ const text = (wert) => (typeof wert === 'string' ? wert : '')
const istConsent = (wert) => wert !== null && typeof wert === 'object' && typeof wert.version === 'string' && typeof wert.knopf === 'string' && Array.isArray(wert.items)
const chatKnopf = () => h('button', { type: 'button', class: 'kb-btn-outline', 'data-view': 'chat' }, 'Frage dazu? Chat öffnen')
/**
* Wo steht das Wartungs-Abo, wenn das Abo-Ende erkannt ist (Behalten)? 'bezahlen': kein Abo (inklusive false UND grund kein_abo), nur dann gibt es
* Behalten gegen 30 €. 'abo': das Abo laeuft (grund nicht_aktiv = Probezeit/Zahlung offen, gekuendigt = Kuendigung vorgemerkt; der Server antwortet
* beim Behalten dort mit 409 „Abo läuft wieder“): nie ein Bezahlknopf (Z12, R20, R25). 'inklusive': enthalten (inklusive true). 'unklar': Abo nicht
* lesbar oder unbekannter Grund (fail-closed, kein Bezahlknopf auf Verdacht). Doppelt zu zeitenBehaltenLage in funktionen.js (die Kachel importiert nichts).
*/
export function behaltenLage(angebot) {
if (angebot?.inklusive === true) return 'inklusive'
if (angebot?.inklusive !== false) return 'unklar'
if (angebot.grund === 'kein_abo') return 'bezahlen'
return angebot.grund === 'nicht_aktiv' || angebot.grund === 'gekuendigt' ? 'abo' : 'unklar'
}
/** Adresse einer Unterlage: https oder /rechtliches/ (sicherLink) oder eine Datei unter /vertragsunterlagen/ dieses Portals, sonst ''. */
function unterlagenLink(url) {
const sicher = sicherLink(url)
@@ -105,7 +118,11 @@ export function renderZeitenBestellen(root, { ctx = {}, angebot = {}, projekt =
if (angebot.inklusive === null || angebot.inklusive === undefined) {
return zeige(h('div', { class: 'kb-panel tm-info zt-hinweis', 'data-hinweis': 'nicht-pruefbar', role: 'alert' }, h('p', null, NICHT_PRUEFBAR), nochmal ? h('button', { type: 'button', class: 'kb-btn-outline', onclick: nochmal }, 'Noch einmal versuchen') : null, zurueck))
}
if (modus === 'behalten' && angebot.inklusive === true) {
if (modus === 'behalten' && behaltenLage(angebot) !== 'bezahlen') {
// das Abo laeuft (wieder) oder ist nicht sicher lesbar: nichts zu bezahlen, nie ein Bezahlknopf auf Verdacht
if (behaltenLage(angebot) === 'unklar') {
return zeige(h('div', { class: 'kb-panel tm-info zt-hinweis', 'data-hinweis': 'nicht-pruefbar', role: 'alert' }, h('p', null, NICHT_PRUEFBAR), nochmal ? h('button', { type: 'button', class: 'kb-btn-outline', onclick: nochmal }, 'Noch einmal versuchen') : null, zurueck))
}
return zeige(h('div', { class: 'kb-panel tm-info zt-hinweis', 'data-hinweis': 'abo-laeuft' }, h('h3', null, 'Dein Wartungs-Abo läuft wieder'), h('p', null, 'Öffnungszeiten live ist darin enthalten – du musst nichts bezahlen.'), zurueck))
}
if (modus === 'behalten') variante = 'behalten'
@@ -265,7 +282,7 @@ function dankeText(danke, feature) {
* projekt = Eintrag aus GET /api/funktionen (projectId, zeitenLeer), feature = projekt.features.zeiten (state, einbau, ticketWoid, orderedAt,
* invoiceUrl, aboEndeAt, disabledReason, loeschungAm), angebot = zeiten (inklusive, preis), kundenansicht = Sitzung in der Kundenansicht,
* danke = 'bestellt' | 'behalten' | 'eingeschaltet' (Rueckkehr von Stripe oder Einschalten), meldung = Text am Knopf.
* behalten() oeffnet die Behalten-Seite (Knopf „Für 30 € behalten“ nur, wenn sicher ist, dass das Abo nicht wieder laeuft: inklusive false);
* behalten() oeffnet die Behalten-Seite (Knopf „Für 30 € behalten“ nur ohne Abo: behaltenLage 'bezahlen', also inklusive false UND grund kein_abo; laeuft das Abo, steht nur der Hinweis);
* weiter({ bestellen, meldung }) wird gerufen, wenn „Zahlung fortsetzen“ scheitert (bestellen: es gibt keine offene Zahlungsseite mehr, die Ansicht
* zeigt wieder die Bestellseite).
*/
@@ -273,7 +290,6 @@ export function zeitenStatusKarte({ projekt, feature, angebot, kundenansicht, da
const state = text(feature?.state) || 'off'
const [pilleText, pilleArt] = PILLE[state] || PILLE.setup
const preis = text(angebot?.preis) || '30 €'
const inklusive = angebot?.inklusive
const leer = projekt?.zeitenLeer === true
const ticket = feature?.ticketWoid
const hatTicket = ticket !== null && ticket !== undefined && String(ticket) !== ''
@@ -309,17 +325,21 @@ export function zeitenStatusKarte({ projekt, feature, angebot, kundenansicht, da
// Behalten (30 €): in Einrichtung/aktiv nach dem erkannten Abo-Ende, abgeschaltet solange die Eingaben noch da sind
const behaltenKnopf = (beschriftung) => h('button', { type: 'button', class: 'kb-btn-outline', 'data-aktion': 'behalten', disabled: sperre, onclick: () => { if (typeof behalten === 'function') behalten() } }, beschriftung)
const behaltenBox = frist && inklusive === false
? h('div', { class: 'tm-box tm-box-warn', role: 'note', 'data-hinweis': 'behalten' },
const lage = behaltenLage(angebot)
let behaltenBox = null
if (frist && lage === 'bezahlen') {
behaltenBox = h('div', { class: 'tm-box tm-box-warn', role: 'note', 'data-hinweis': 'behalten' },
h('span', null, `Dein Wartungs-Abo ist beendet – behalte die Funktion bis ${frist} für einmalig ${preis}.`),
behaltenKnopf(`Für ${preis} behalten`))
: null
} else if (frist && lage === 'abo') {
behaltenBox = h('div', { class: 'tm-box tm-box-info', role: 'note', 'data-hinweis': 'abo-laeuft' }, h('span', null, 'Dein Wartungs-Abo läuft wieder – Öffnungszeiten live ist darin enthalten.'))
}
let abgeschaltetBox = null
if (daten && inklusive === false) {
if (daten && lage === 'bezahlen') {
abgeschaltetBox = h('div', { class: 'tm-box tm-box-warn', role: 'note', 'data-hinweis': 'wieder-einschalten' },
h('span', null, `Deine Eingaben bleiben${tagText(feature?.loeschungAm) ? ` bis ${tagText(feature.loeschungAm)}` : ''} gespeichert. Für einmalig ${preis} schaltest du die Funktion wieder ein.`),
behaltenKnopf(`Für ${preis} wieder einschalten`))
} else if (daten && inklusive === true) {
} else if (daten && (lage === 'inklusive' || lage === 'abo')) {
abgeschaltetBox = h('div', { class: 'tm-box tm-box-info', role: 'note', 'data-hinweis': 'abo-laeuft' }, h('span', null, 'Dein Wartungs-Abo läuft wieder – wir schalten Öffnungszeiten live automatisch wieder ein (meist innerhalb eines Tages).'))
} else if (daten) {
abgeschaltetBox = h('div', { class: 'tm-box tm-box-info', role: 'note', 'data-hinweis': 'nicht-pruefbar' }, h('span', null, NICHT_PRUEFBAR))