Öffnungszeiten: nach Abo-Ende für 30 € behalten

Neuer Modus neben Bestellen und Einschalten (Spec 3.3): POST /api/funktionen/zeiten/behalten
startet einen Checkout mit zweck 'behalten', ohne den Zustand zu ändern; der Webhook-Zweig
bucht vor markPaid/adoptPaidSession unter feature-admin zum Kauf (Frist weg, stripeSessionId =
Sitzung), schaltet eine abgeschaltete Funktion wieder ein (Neubau nach der Sperre), ohne neues
Ticket, mit K15 im Behalten-Wortlaut. Passt die Sitzung nicht, geht T19 nach der Sperre raus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-05 02:54:39 +00:00
1 parent 97e6971276
commit 53253f0451
6 files changed
+1116 -12

No files matched your search

+11 -4
View File
@@ -655,15 +655,22 @@ export async function createAboCheckout(customer, consent, productKey, offer = n
* 24 Stunden (Stripe-Hoechstwert; fuenf Minuten Luft fuer die Laufzeit des Aufrufs), die Rechnung erzeugt Stripe
* selbst und traegt featureKey und projectId in ihren Metadaten. Nur die Zuordnung steht in den Metadaten der Sitzung,
* der Zustimmungswortlaut nicht.
* zweck: 'behalten' (Oeffnungszeiten live nach dem Abo-Ende, Spec 3.3) steht in den Metadaten der Sitzung und der Rechnung, damit der
* Webhook die Zahlung nicht als Neubestellung verbucht, und die Rueckkehr traegt `behalten=1` statt `bestellt=1`; ohne zweck bleibt alles wie es war.
* @returns {Promise<{ id: string, url: string }>}
*/
export async function createFeatureCheckout(customer, { projectId, key = 'news', consentAt }) {
export async function createFeatureCheckout(customer, { projectId, key = 'news', consentAt, zweck = null }) {
const feature = featureConfig(key)
if (!feature) {
const err = new Error('Unbekannte Funktion.')
err.status = 400
throw err
}
if (zweck !== null && zweck !== 'behalten') {
const err = new Error('Unbekannter Zweck.')
err.status = 400
throw err
}
const stripe = getStripe()
const [priceId, stripeCustomerId] = await Promise.all([ensurePrice(feature.product), getOrCreateStripeCustomer(customer)])
// Rueckkehr ins Dashboard: bei Funktionen mit returnProjekt (Terminplaner) mit dem Projekt, damit die Seite es oeffnet
@@ -683,12 +690,12 @@ export async function createFeatureCheckout(customer, { projectId, key = 'news',
invoice_data: {
description: catalogFor(feature.product).name,
footer: config.stripe.invoiceFooter,
metadata: { featureKey: key, projectId },
metadata: { featureKey: key, projectId, ...(zweck ? { zweck } : {}) },
},
},
metadata: { customerId: customer.$id, projectId, featureKey: key, ...(consentAt ? { consentAt } : {}) },
metadata: { customerId: customer.$id, projectId, featureKey: key, ...(consentAt ? { consentAt } : {}), ...(zweck ? { zweck } : {}) },
expires_at: Math.floor(Date.now() / 1000) + 24 * 60 * 60 - 5 * 60,
success_url: `${returnUrl}?bestellt=1${projekt ? `&projekt=${projekt}` : ''}`,
success_url: `${returnUrl}?${zweck === 'behalten' ? 'behalten' : 'bestellt'}=1${projekt ? `&projekt=${projekt}` : ''}`,
cancel_url: `${returnUrl}${projekt ? `?projekt=${projekt}` : ''}`,
}
let session