diff --git a/server/routes/abo.js b/server/routes/abo.js index 81a03ba..805405d 100644 --- a/server/routes/abo.js +++ b/server/routes/abo.js @@ -16,6 +16,7 @@ import { createBillingPortalUrl, getCurrentSubscription, grantCreditForInvoice, + minTermMonthsFor, isStripeConfigured, syncSubscription, } from '../services/stripeBilling.js' @@ -46,7 +47,8 @@ function addMonthsIso(iso, months) { function minTermEndOf(sub) { const start = sub?.trialEnd || sub?.startedAt - return start ? addMonthsIso(start, config.abo.minTermMonths) : null + const months = minTermMonthsFor(sub?.termsVersion) + return start && months ? addMonthsIso(start, months) : null } function publicSubscription(sub) { @@ -179,8 +181,12 @@ async function sendContractConfirmation(subDoc) { ' Preis: 50,00 € pro Monat (gemäß § 19 UStG ohne Umsatzsteuer)', ` Vertragsschluss: ${fmtDate(subDoc.startedAt)}`, ` Leistungsbeginn: ${lateStart ? fmtDate(subDoc.trialEnd) : fmtDate(subDoc.startedAt)}`, - ` Laufzeit: Mindestlaufzeit 12 Monate bis ${fmtDate(minTermEndOf(subDoc))}; Kündigung zu diesem Termin bis einen Monat vorher,`, - ' danach läuft das Abo unbefristet und ist jederzeit zum Ende des Abrechnungsmonats kündbar', + ...(minTermEndOf(subDoc) + ? [ + ` Laufzeit: Mindestlaufzeit 12 Monate bis ${fmtDate(minTermEndOf(subDoc))}; Kündigung zu diesem Termin bis einen Monat vorher,`, + ' danach läuft das Abo unbefristet und ist jederzeit zum Ende des Abrechnungsmonats kündbar', + ] + : [' Laufzeit: unbestimmt, jederzeit zum Ende des Abrechnungsmonats kündbar']), ' Enthalten: Betrieb und Pflege Ihrer Website bzw. Web-Anwendung, 1 Domain, 1 E-Mail-Postfach,', ' 1 Stunde Arbeitszeit je bezahltem Monat (12 Monate nutzbar)', '', diff --git a/server/services/stripeBilling.js b/server/services/stripeBilling.js index 81ebff1..3e7429b 100644 --- a/server/services/stripeBilling.js +++ b/server/services/stripeBilling.js @@ -200,7 +200,7 @@ function addMonths(date, months) { * - Wunschtermin: fruehestens zum berechneten Zeitpunkt, sonst zum Ende des Abrechnungsmonats, * in dem der Wunschtermin liegt */ -export function computeCancellationDate({ serviceStart, receivedAt = new Date(), requestedDate = null, kind = 'ordentlich' }) { +export function computeCancellationDate({ serviceStart, receivedAt = new Date(), requestedDate = null, kind = 'ordentlich', minTermMonths = config.abo.minTermMonths }) { const start = new Date(serviceStart) const boundary = (k) => addMonths(start, k) const firstBoundaryFrom = (minK, notBefore) => { @@ -208,7 +208,7 @@ export function computeCancellationDate({ serviceStart, receivedAt = new Date(), while (boundary(k) < notBefore) k += 1 return k } - const minTermK = config.abo.minTermMonths + const minTermK = minTermMonths let k if (kind === 'geschaeftsaufgabe') { k = firstBoundaryFrom(1, addMonths(receivedAt, 1)) @@ -220,6 +220,11 @@ export function computeCancellationDate({ serviceStart, receivedAt = new Date(), return { effectiveAt: boundary(k), minTermEnd: boundary(minTermK), serviceStart: start } } +/** Es gilt die Mindestlaufzeit der Bedingungen, denen der Kunde zugestimmt hat (erst ab Version 3). */ +export function minTermMonthsFor(termsVersion) { + return ['2026-09-25', '2026-09-25-v2'].includes(termsVersion) ? 0 : config.abo.minTermMonths +} + export function serviceStartOf(sub) { return new Date(((sub.trial_end || sub.start_date) || 0) * 1000) } @@ -425,6 +430,7 @@ export async function cancelSubscriptionAt(subscriptionId, requestedDate = null, receivedAt, requestedDate, kind, + minTermMonths: minTermMonthsFor(sub.metadata?.termsVersion), }) const periodEnd = periodEndOf(sub) const effectiveUnix = Math.floor(effectiveAt.getTime() / 1000)