Mails K15/K16 je Funktion (News-Wortlaut eingefroren)

K15 (Bestellung eingegangen) und K16 (Funktion bereit) tragen den Wortlaut der
Funktion als Platzhalter (funktion, funktion_gen/akk/nom/pron/dein, preis_hinweis,
danach, bereit, knopf, portal_url) statt fest News-Pinnwand. siteFeatures baut die
Werte mit bestellMail/bereitMail aus dem Register-Eintrag (mails.*, setupEstimate,
returnHash) und dem Katalogpreis je feature.product. K15 geht ohne Anhaenge raus.
Die News-Mails bleiben Zeichen fuer Zeichen gleich (Test featureMails friert
Betreff und Text ein).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-04 12:56:45 +00:00
1 parent 9dd0244537
commit e200efb7e5
5 files changed
+421 -37

No files matched your search

+66 -16
View File
@@ -469,7 +469,60 @@ export async function findActiveBySiteKey(siteKey, featureKey = 'news') {
// ---------------------------------------------------------------------------
const eur = (cents) => `${(cents / 100).toFixed(2).replace('.', ',')} €`
const portalUrl = () => `${config.publicBaseUrl}/dashboard.html#news`
/** Adresse der Funktion im Kundenportal (Anker aus dem Register: returnHash). */
const portalUrl = (feature) => `${config.publicBaseUrl}/dashboard.html#${feature.returnHash}`
/** Preis der Einrichtung aus dem Katalog der Funktion (feature.product: newsSetup | termineSetup); config.* bei jedem Aufruf gelesen. */
function einrichtungsPreis(feature) {
const amountCents = config[feature.product]?.amountCents
if (!Number.isInteger(amountCents)) throw new Error(`Katalogpreis ${feature.product} fehlt`)
return eur(amountCents)
}
/**
* K15 (Bestellung eingegangen) einer Funktion: Vorlage, Platzhalterwerte und Bloecke ausschliesslich aus dem Register-Eintrag
* (mails.*, setupEstimate, returnHash) und dem Katalogpreis. Die Werte decken genau die Platzhalter der Vorlage ab.
* Ohne Anhaenge: die Rechtsunterlagen der Termine-Bestellung haengt F8 direkt in onFeaturePaid an.
*/
export function bestellMail(feature, { kundeName, projekt, invoiceUrl }) {
const { funktion, formen, preisHinweis, danach } = feature.mails
return {
template: 'K15',
values: {
kunde_name: kundeName,
projekt,
funktion,
funktion_gen: formen.gen,
funktion_akk: formen.akk,
funktion_nom: formen.nom,
funktion_pron: formen.pron,
preis: einrichtungsPreis(feature),
preis_hinweis: preisHinweis,
zeit: feature.setupEstimate,
danach,
portal_url: portalUrl(feature),
rechnung_url: invoiceUrl || '',
},
blocks: { rechnung: Boolean(invoiceUrl) },
}
}
/** K16 (Funktion bereit) einer Funktion, Werte wie bei bestellMail aus dem Register-Eintrag. */
export function bereitMail(feature, { kundeName, projekt }) {
const { funktion, formen, bereit, knopf } = feature.mails
return {
template: 'K16',
values: {
kunde_name: kundeName,
projekt,
funktion,
funktion_dein: formen.dein,
funktion_nom: formen.nom,
bereit,
knopf,
portal_url: portalUrl(feature),
},
}
}
/** Ereignisse, die handleFeatureCheckoutEvent versteht (Funktions-Checkout: mode 'payment' mit featureKey). */
export const FEATURE_EVENT_TYPES = [
@@ -595,17 +648,12 @@ async function onFeaturePaid(session) {
}
if (customer?.email) {
try {
await sendCustomerMail(customer.email, {
template: 'K15',
values: {
kunde_name: customer.name || '',
projekt: await projectName(doc.projectId),
preis: eur(config.newsSetup.amountCents),
zeit: config.funktionen.setupEstimate,
rechnung_url: invoiceUrl,
},
blocks: { rechnung: Boolean(invoiceUrl) },
})
const feature = featureConfig(doc.featureKey)
if (!feature) throw new Error(`Funktion ${doc.featureKey} nicht im Register`)
await sendCustomerMail(
customer.email,
bestellMail(feature, { kundeName: customer.name || '', projekt: await projectName(doc.projectId), invoiceUrl })
)
} catch (err) {
console.error('[funktionen] K15 fehlgeschlagen:', err.message)
}
@@ -647,10 +695,12 @@ export async function runActivation({ now = new Date(), customerId = null } = {}
try {
const customer = await customerOf(doc.customerId)
if (!customer?.email) continue
await sendCustomerMail(customer.email, {
template: 'K16',
values: { kunde_name: customer.name || '', projekt: await projectName(doc.projectId), portal_url: portalUrl() },
})
const feature = featureConfig(doc.featureKey)
if (!feature) throw new Error(`Funktion ${doc.featureKey} nicht im Register`)
await sendCustomerMail(
customer.email,
bereitMail(feature, { kundeName: customer.name || '', projekt: await projectName(doc.projectId) })
)
} catch (err) {
console.error(`[funktionen] K16 an Kunde ${doc.customerId} fehlgeschlagen:`, err.message)
}