146 lines
7.3 KiB
JavaScript
146 lines
7.3 KiB
JavaScript
import { config } from '../config.js'
|
|
import { anleitungsLink, featureConfig, katalogFelder } from './featureRegistry.js'
|
|
import { unterlagenFuer } from './aboUnterlagen.js'
|
|
import { LOESCHFRIST_TAGE } from './termine/frist.js'
|
|
import { datumKurz } from './termine/zeit.js'
|
|
|
|
/**
|
|
* Mails der Funktionen im Abo-Modell (Kundenansicht neu, P6; Vorlagen server/mail-templates/K38, K39, T24):
|
|
* K38 Deine Funktion wird eingerichtet (Einschalten aus dem Abo oder durch das Team; nicht für Öffnungszeiten live, dort bleibt K27)
|
|
* K39 Deine Funktion wurde beendet (der Tagesabgleich beendet sie mit dem Abo)
|
|
* T24 Team-Hinweis: Funktion eingeschaltet (Einrichtung geht aufs Stundenkonto, Block vorschuss)
|
|
* K42, K43 Webshop- und Buchungskalender-Anfrage entschieden (Zusage oder Absage), Ersatz fuer K24 und K34 im Abo-Modell: ohne Preis und ohne
|
|
* das Wort "bestellen" (anfrageEntschiedenMail)
|
|
* Die Builder sind rein (kein Zugriff auf Appwrite, kein Versand) und liefern { template, values, blocks }, so wie
|
|
* zeiten/mails.js: die Werte decken genau die Platzhalter der Vorlage ab. Keine Preise, kein Wort „bestellen“.
|
|
*
|
|
* Anrede: `kunde` ist der Name oder das Kundendokument; ohne Namen bleibt kunde_name leer (renderMail macht aus „Hallo ,“ „Hallo,“).
|
|
*/
|
|
|
|
/** Anrede-Wert: Name aus einem String oder einem Kundendokument, getrimmt; sonst ''. */
|
|
function kundenName(kunde) {
|
|
const name = typeof kunde === 'string' ? kunde : kunde?.name
|
|
return typeof name === 'string' ? name.trim() : ''
|
|
}
|
|
|
|
/** Date -> 'TT.MM.JJJJ' (Berliner Tag). Wirft bei etwas anderem als einem gültigen Date: ein leeres Datum in der Mail wäre falsch. */
|
|
function datum(wert, feld) {
|
|
if (!(wert instanceof Date) || Number.isNaN(wert.getTime())) throw new TypeError(`${feld}: gültiges Date erwartet`)
|
|
return datumKurz(wert)
|
|
}
|
|
|
|
/** Registereintrag einer Funktion; ein unbekannter Schlüssel ist ein Programmfehler (TypeError). */
|
|
function funktion(key) {
|
|
const eintrag = featureConfig(key)
|
|
if (!eintrag) throw new TypeError(`Unbekannte Funktion: ${String(key)}`)
|
|
return eintrag
|
|
}
|
|
|
|
/** Adresse der Funktion im Kundenportal (returnHash des Registers). */
|
|
const portalUrl = (eintrag) => `${config.publicBaseUrl}/dashboard.html#${eintrag.returnHash}`
|
|
|
|
/**
|
|
* K38: Die Funktion wird eingerichtet.
|
|
* @param {{ kunde: string | { name?: string }, projekt: string, key: string, abrechnung: 'abo' | 'projekt', ticketNr?: string | number | null, anhang?: boolean }} p
|
|
* abrechnung: 'abo' (Einrichtung geht vom Stundenkonto ab, Block stundenkonto) oder 'projekt' (Teil der Projektkosten, Block projekt_kosten);
|
|
* ticketNr: Nummer des Einrichtungs-Tickets (mit oder ohne #), ohne sie steht kein Ticket in der Mail;
|
|
* anhang: Leistungsbeschreibung und Auftragsverarbeitung hängen als PDF an (Block anhang).
|
|
*/
|
|
export function k38Mail({ kunde, projekt, key, abrechnung, ticketNr = null, anhang = false }) {
|
|
const eintrag = funktion(key)
|
|
const nr = String(ticketNr ?? '').trim().replace(/^#/, '')
|
|
return {
|
|
template: 'K38',
|
|
values: {
|
|
kunde_name: kundenName(kunde),
|
|
projekt,
|
|
funktion: eintrag.mails.funktion,
|
|
funktion_akk: eintrag.mails.formen.akk,
|
|
einrichtung: katalogFelder(key).einrichtung,
|
|
// führendes Leerzeichen: steht direkt hinter dem Projektnamen, ohne Ticket bleibt nichts übrig
|
|
ticket: nr ? ` (Ticket #${nr})` : '',
|
|
fassung: unterlagenFuer(key).leistungsbeschreibung?.version ?? '',
|
|
portal_url: portalUrl(eintrag),
|
|
},
|
|
blocks: { stundenkonto: abrechnung === 'abo', projekt_kosten: abrechnung === 'projekt', anhang: anhang === true },
|
|
}
|
|
}
|
|
|
|
/**
|
|
* K39: Die Funktion wurde mit dem Abo beendet.
|
|
* @param {{ kunde: string | { name?: string }, projekt: string, key: string, loeschdatum: Date, art: string }} p
|
|
* loeschdatum: Tag, ab dem die Eingaben gelöscht werden; art: 'hosting' (das Abo ist ein Hosting-Abo), sonst (auch 'beendet') Abo beendet.
|
|
* Zusatzblöcke: termine nur beim Terminplaner, offene nur bei Webshop und Buchungskalender (unterkunft).
|
|
*/
|
|
export function k39Mail({ kunde, projekt, key, loeschdatum, art }) {
|
|
const eintrag = funktion(key)
|
|
return {
|
|
template: 'K39',
|
|
values: {
|
|
kunde_name: kundenName(kunde),
|
|
projekt,
|
|
funktion: eintrag.mails.funktion,
|
|
loeschtag: datum(loeschdatum, 'loeschdatum'),
|
|
portal_url: portalUrl(eintrag),
|
|
},
|
|
blocks: { abo_ende: art !== 'hosting', hosting: art === 'hosting', termine: key === 'termine', offene: key === 'shop' || key === 'unterkunft' },
|
|
}
|
|
}
|
|
|
|
/**
|
|
* T24: Team-Hinweis, dass eine Funktion eingeschaltet wurde.
|
|
* @param {{ kunde: string | { name?: string }, email: string, projekt: string, key: string, customerId: string, projectId: string, woid: string,
|
|
* kontostand?: string, anhangFehlt?: boolean }} p
|
|
* kontostand: Text aus kontostandText(), nur gesetzt, wenn das Guthaben beim Einschalten nicht reicht (Block vorschuss);
|
|
* anhangFehlt: die Vertragsunterlagen sind nicht beim Kunden angekommen (Block anhang_fehlt).
|
|
*/
|
|
export function t24Mail({ kunde, email, projekt, key, customerId, projectId, woid, kontostand = '', anhangFehlt = false }) {
|
|
const eintrag = funktion(key)
|
|
return {
|
|
template: 'T24',
|
|
values: {
|
|
kunde_name: kundenName(kunde),
|
|
email: String(email ?? ''),
|
|
projekt,
|
|
funktion: eintrag.mails.funktion,
|
|
woid: String(woid ?? ''),
|
|
kontostand,
|
|
woms_url: anleitungsLink(customerId, projectId),
|
|
},
|
|
blocks: { vorschuss: kontostand !== '', anhang_fehlt: anhangFehlt === true },
|
|
}
|
|
}
|
|
|
|
/**
|
|
* K42 (Webshop) oder K43 (Buchungskalender): die Anfrage wurde vom Team entschieden. Im Abo-Modell ohne Preiszeile und ohne "bestellen":
|
|
* bei Zusage kann der Kunde die Funktion im Kundenportal einschalten. Werte und Adresse wie die alten Mails K24 und K34 (sendeEntscheidung).
|
|
* @param {{ kunde: string | { name?: string }, projekt: string, key: 'shop' | 'unterkunft', projectId: string, angenommen: boolean, begruendung?: string }} p
|
|
* kunde_name ist der getrimmte Name, leer 'Kunde'; ein anderer key ist ein TypeError.
|
|
*/
|
|
export function anfrageEntschiedenMail({ kunde, projekt, key, projectId, angenommen, begruendung = '' }) {
|
|
if (key !== 'shop' && key !== 'unterkunft') throw new TypeError(`Keine Anfrage-Mail fuer die Funktion: ${String(key)}`)
|
|
const eintrag = funktion(key)
|
|
return {
|
|
template: key === 'shop' ? 'K42' : 'K43',
|
|
values: {
|
|
kunde_name: kundenName(kunde) || 'Kunde',
|
|
projekt,
|
|
begruendung,
|
|
portal_url: `${config.publicBaseUrl}/dashboard.html#${eintrag.returnHash}?projekt=${encodeURIComponent(projectId)}`,
|
|
},
|
|
blocks: { angenommen: Boolean(angenommen), abgelehnt: !angenommen },
|
|
}
|
|
}
|
|
|
|
/** Tage zwischen dem Abschalten und der Löschung der Eingaben: news 30, termine 30, shop und unterkunft aus der Konfiguration; sonst TypeError. */
|
|
export function loeschFristTage(key) {
|
|
if (key === 'news') return 30
|
|
if (key === 'termine') return LOESCHFRIST_TAGE
|
|
if (key === 'shop') return config.shop.loeschTageNachAbschalten
|
|
if (key === 'unterkunft') return config.unterkunft.loeschTageNachAbschalten
|
|
throw new TypeError(`Keine Löschfrist für die Funktion: ${String(key)}`)
|
|
}
|
|
|
|
/** Kontostand für T24, z. B. 'Guthaben 0 min, Vorschuss 90 min'. */
|
|
export const kontostandText = ({ balanceMinutes = 0, vorschussMinutes = 0 }) => `Guthaben ${balanceMinutes} min, Vorschuss ${vorschussMinutes} min`
|