Kundenansicht P6: Ticket-Texte zum Stundenkonto je Abrechnung (Abo, Projekt)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-16 16:54:52 +00:00
1 parent df53cd039b
commit bb1efa5c9e
5 files changed
+80 -7

No files matched your search

+2 -1
View File
@@ -54,7 +54,8 @@ export async function shopTicketDetails(ctx) {
`5. Vorschau prüfen: https://project.webklar.com/shop/${siteKey}`,
'6. Ticket schließen: das schaltet die Funktion frei.',
'',
'Zeit im Arbeitsblatt erfassen, nicht auf Abo-Stunden anrechnen.',
// Abo-Modell (einrichtungAbrechnung abo oder projekt): die Abrechnung steht allein in der Schlusszeile des Tickets (createFeatureTicket)
...(doc?.einrichtungAbrechnung === 'abo' || doc?.einrichtungAbrechnung === 'projekt' ? [] : ['Zeit im Arbeitsblatt erfassen, nicht auf Abo-Stunden anrechnen.']),
`Verweis: ${anleitungsLink(doc?.customerId, doc?.projectId)}`,
]
return kuerze(zeilen.join('\n').toWellFormed(), TICKET_DETAILS_MAX, { anZeile: true })
+27 -3
View File
@@ -488,6 +488,19 @@ const DATENSCHUTZ_REGEL =
'liegt die Datenschutzerklärung in der von WEBklar betreuten Website, fügen wir den Absatz beim Einbau ein, das gehört zur Einrichtung und wird nicht auf das Stundenkontingent angerechnet; '
+ 'sonst den Absatz als Textbaustein per Chat an den Kunden senden, der ihn selbst einfügt'
/**
* Abrechnung am Dokument (einrichtungAbrechnung, Abo-Modell der Kundenansicht neu): 'abo' (aufs Abo-Stundenkonto) oder 'projekt' (im Projekt
* enthalten); alles andere (Kauf-Bestand, Pilot, Kulanz) ist '' und behaelt die bisherigen Texte Zeichen fuer Zeichen.
*/
const abrechnungVon = (feature) => (feature?.einrichtungAbrechnung === 'abo' || feature?.einrichtungAbrechnung === 'projekt' ? feature.einrichtungAbrechnung : '')
/** DATENSCHUTZ_REGEL je Abrechnung: ohne Marker die Konstante wörtlich, im Abo-Modell ohne "nicht angerechnet". */
function datenschutzRegel(feature) {
const abrechnung = abrechnungVon(feature)
if (!abrechnung) return DATENSCHUTZ_REGEL
return DATENSCHUTZ_REGEL.replace('wird nicht auf das Stundenkontingent angerechnet', abrechnung === 'abo' ? 'zählt mit zum Stundenkonto' : 'ist im Projekt enthalten')
}
function abschnittCheckliste(d) {
const { e } = d
const widerruf = zeigtWiderruf(e)
@@ -501,7 +514,7 @@ function abschnittCheckliste(d) {
'Einbau-Code eingefügt (Abschnitt „Einbau-Code (Snippet)“). Das Widget bleibt unsichtbar bis zur Freischaltung: Bis dahin steht nur der Ausweichtext auf der Seite.',
...(knopf ? ['Modus knopf: --wkt-akzent immer setzen (Abschnitt „Aussehen (CSS)“). Der Knopf kennt die Betriebsfarbe erst nach dem Klick und nimmt sonst #1d4ed8.'] : []),
'Ausweichtext geprüft: JavaScript aus oder falscher siteKey: Der Text steht, nichts ist kaputt.',
`Datenschutz-Absatz „Online-Terminbuchung“ steht in der Datenschutzerklärung der Website (Fassung ${e.anrede === 'du' ? 'Du' : 'Sie'}; ${DATENSCHUTZ_REGEL}).`,
`Datenschutz-Absatz „Online-Terminbuchung“ steht in der Datenschutzerklärung der Website (Fassung ${e.anrede === 'du' ? 'Du' : 'Sie'}; ${datenschutzRegel(d.feature)}).`,
`URLs von Impressum (${impressum}) und Datenschutzerklärung (${datenschutz}) stimmen und beginnen mit https://, sonst fehlen die Links im Fuß des Widgets.`,
`„Freischalten (Abnahme)“ im Ticketsystem ausgelöst${wo}. Erst danach antwortet die öffentliche Schnittstelle (nur im Zustand active), und das Widget erscheint.`,
// am sichtbaren Widget
@@ -531,6 +544,16 @@ function einrichtungsPreis() {
}
function abschnittAbrechnung(d) {
const abrechnung = abrechnungVon(d.feature)
if (abrechnung) {
// Abo-Modell: Einrichtung ohne Zahlung, die Zeit gehoert aufs Abo-Stundenkonto bzw. ins Projekt
return neuerAbschnitt('abrechnung', 'Abrechnung', [
abrechnung === 'abo'
? 'Abrechnung: Einrichtung aus dem Abo, Zeit im Arbeitsblatt aufs Abo-Stundenkonto anrechnen (Vorschuss möglich).'
: 'Abrechnung: im Projekt enthalten, Zeit im Arbeitsblatt, nicht aufs Abo anrechnen.',
'Leistungsumfang: ein Widget an einer Stelle, Gestaltung nach Fragebogen, Einbau; Mehrwünsche (zweites Widget, Knöpfe je Leistung, Sonderdesign) nach Stunden, vorher im Chat abstimmen.',
].join('\n'))
}
if (d.feature?.unlockedByPurchase !== true) {
return neuerAbschnitt('abrechnung', 'Abrechnung', 'Abrechnung: ohne Zahlung freigeschaltet (Pilot/Kulanz), keine Abrechnung.')
}
@@ -663,14 +686,15 @@ function kurzUmfang(k) {
function kurzSchritte(k) {
const form = !k.hatEinstellung ? 'Sie- oder Du-Form nach der Anrede der Gäste' : k.anrede === 'du' ? 'Du-Form' : 'Sie-Form'
const bezahlt = k.feature?.unlockedByPurchase === true ? ` (Einrichtung bezahlt, ${einrichtungsPreis()})` : ''
const abrechnung = abrechnungVon(k.feature)
return [
'Schritte:',
'1. WOMS-Panel öffnen (Kunde → Reiter Funktionen → Anleitung des Projekts): dort stehen alle Einstellungen, die Kopierknöpfe und die Abnahme-Checkliste.',
'2. Einbau-Code einfügen: den Code oben an der Stelle einsetzen, die der Kunde nennt (siehe Kundenwunsch), das Skript einmal pro Seite.',
'3. Gestaltung und Kontrast: das CSS aus der Anleitung (Abschnitt „Aussehen (CSS)“) in die Website übernehmen und den Kontrast prüfen.',
`4. Datenschutz-Absatz (${form}) aus der Anleitung in die Datenschutzerklärung der Website aufnehmen, bevor freigeschaltet wird (${DATENSCHUTZ_REGEL}).`,
`4. Datenschutz-Absatz (${form}) aus der Anleitung in die Datenschutzerklärung der Website aufnehmen, bevor freigeschaltet wird (${datenschutzRegel(k.feature)}).`,
'5. „Freischalten (Abnahme)“ im WOMS auslösen, danach eine Probebuchung durchspielen und den Testtermin wieder stornieren (Checkliste in der Anleitung).',
`6. Ticket erledigen und die Zeit im Arbeitsblatt buchen. Nicht auf das Stundenkontingent anrechnen${bezahlt}.`,
abrechnung ? '6. Ticket erledigen und die Zeit im Arbeitsblatt buchen.' : `6. Ticket erledigen und die Zeit im Arbeitsblatt buchen. Nicht auf das Stundenkontingent anrechnen${bezahlt}.`,
].join('\n')
}
+4 -2
View File
@@ -36,13 +36,15 @@ export async function termineTicketDetails(ctx) {
const ANLEITUNG_FEHLT = 'Anleitung konnte nicht erzeugt werden, im WOMS öffnen (Verweis oben).'
const KONTINGENT = 'Nicht auf das Stundenkontingent anrechnen.'
// Abo-Modell (Kundenansicht neu, P6): die Abrechnung steht allein in der Schlusszeile des Tickets (createFeatureTicket, ABRECHNUNGS_ZEILEN)
const imAboModell = (doc) => doc?.einrichtungAbrechnung === 'abo' || doc?.einrichtungAbrechnung === 'projekt'
/** Kopfzeilen und Verweis (minimaleTicketDetails, Funktion wie im Kopf der Kurzfassung) plus Hinweis; wirft nie, auch nicht bei einem unbrauchbaren ctx. */
function notfallDetails(ctx) {
try {
const kopf = minimaleTicketDetails({ ...ctx, feature: { key: 'Terminplaner' } })
return kuerze(`${kopf}\n${ANLEITUNG_FEHLT}\n${KONTINGENT}`.toWellFormed(), TICKET_DETAILS_MAX)
return kuerze(`${kopf}\n${ANLEITUNG_FEHLT}${imAboModell(ctx?.doc) ? '' : `\n${KONTINGENT}`}`.toWellFormed(), TICKET_DETAILS_MAX)
} catch {
return `Funktion: Terminplaner\nAnleitung konnte nicht erzeugt werden, im WOMS öffnen (Kunden → Funktionen).\n${KONTINGENT}`
return `Funktion: Terminplaner\nAnleitung konnte nicht erzeugt werden, im WOMS öffnen (Kunden → Funktionen).${imAboModell(ctx?.doc) ? '' : `\n${KONTINGENT}`}`
}
}
+2 -1
View File
@@ -46,7 +46,8 @@ export async function unterkunftTicketDetails(ctx) {
'5. Testanfrage über den Kalender stellen und im Portal (Buchungen) prüfen.',
'6. Ticket schließen: das schaltet die Funktion frei (sobald der Kunde Unterkunft, Preise, Stornobedingungen und Firmendaten hinterlegt hat).',
'',
'Zeit im Arbeitsblatt erfassen, nicht auf Abo-Stunden anrechnen.',
// Abo-Modell (einrichtungAbrechnung abo oder projekt): die Abrechnung steht allein in der Schlusszeile des Tickets (createFeatureTicket)
...(doc?.einrichtungAbrechnung === 'abo' || doc?.einrichtungAbrechnung === 'projekt' ? [] : ['Zeit im Arbeitsblatt erfassen, nicht auf Abo-Stunden anrechnen.']),
'Einbauanleitung: docs/funktionen/unterkunft-einbau.md',
`Verweis: ${anleitungsLink(doc?.customerId, doc?.projectId)}`,
]