Abo: Kuendigungsbestaetigung auch bei Kuendigung ueber das Stripe-Kundenportal

Webhook customer.subscription.updated erkennt neu gesetzte Kuendigungen.
Kuendigungs- und Widerrufsseite markieren ihre Kuendigung per Metadatum
cancelSource, damit keine doppelte Bestaetigung verschickt wird.
Admin-Hinweis auch bei zurueckgenommener Kuendigung.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-09-25 17:45:04 +00:00
1 parent 90e85f5989
commit 9e21aa0690
2 files changed
+66 -7

No files matched your search

+12 -4
View File
@@ -373,8 +373,12 @@ export async function createBillingPortalUrl(customerId) {
}
/** Ordentliche Kuendigung zum Ende des bezahlten Monats. */
export async function cancelAtPeriodEnd(subscriptionId) {
await getStripe().subscriptions.update(subscriptionId, { cancel_at_period_end: true })
export async function cancelAtPeriodEnd(subscriptionId, source = 'system') {
// cancelSource: der Webhook erkennt daran, dass die Bestaetigung schon verschickt wird
await getStripe().subscriptions.update(subscriptionId, {
cancel_at_period_end: true,
metadata: { cancelSource: source },
})
return syncSubscription(subscriptionId)
}
@@ -383,13 +387,16 @@ export async function cancelAtPeriodEnd(subscriptionId) {
* der Wunschtermin liegt (ohne Wunschtermin: Ende des laufenden Monats).
* Liefert das Abo-Dokument und den Beendigungszeitpunkt (ISO).
*/
export async function cancelSubscriptionAt(subscriptionId, requestedDate = null) {
export async function cancelSubscriptionAt(subscriptionId, requestedDate = null, source = 'kuendigungsbutton') {
const stripe = getStripe()
const sub = await stripe.subscriptions.retrieve(subscriptionId)
const periodEnd = periodEndOf(sub)
const requested = requestedDate ? Math.floor(requestedDate.getTime() / 1000) : null
if (!requested || !periodEnd || requested <= periodEnd) {
await stripe.subscriptions.update(subscriptionId, { cancel_at_period_end: true })
await stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true,
metadata: { cancelSource: source },
})
const doc = await syncSubscription(subscriptionId)
return { subscription: doc, effectiveAt: toIso(periodEnd) }
}
@@ -400,6 +407,7 @@ export async function cancelSubscriptionAt(subscriptionId, requestedDate = null)
await stripe.subscriptions.update(subscriptionId, {
cancel_at: Math.floor(boundary.getTime() / 1000),
proration_behavior: 'none',
metadata: { cancelSource: source },
})
const doc = await syncSubscription(subscriptionId)
return { subscription: doc, effectiveAt: boundary.toISOString() }