Zustimmungsnachweis je Funktion (featureConsents) und Fristanker aus dem Klick
server/services/featureConsents.js speichert und liest den Nachweis zur Bestellung einer Funktion (nur anfuegen, sieben Exporte): speichereZustimmung (Texte und Fassungen als JSON, SHA-256 ueber die Texte, vollstaendig oder gar nicht), letzteZustimmung, zustimmungFuerSitzung (leere Sitzung fragt nicht ab), leseZustimmung, texteHash, zustimmungsfassungen und nachweisTexte (Haken, Belehrung, Knopf aus dem Register). paidFeatureOrders liefert featureKey und vertragAt (Klick der bezahlten Sitzung, sonst consentAt, sonst orderedAt; Lesefehler faellt mit Log auf orderedAt zurueck); der Widerruf einer Funktion rechnet die Frist aus vertragAt. Eine spaetere, unbezahlte Zustimmung verschiebt den Anker nicht. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d8e4d79891
commit
786df1230e
5 files changed
+627
-4
No files matched your search
@@ -5,6 +5,7 @@ import { withLocks } from './keyedLock.js'
|
||||
import { sendAdminNotice, sendCustomerMail } from './mailer.js'
|
||||
import { getStripe, retrieveCheckoutSession } from './stripeBilling.js'
|
||||
import { featureConfig, featureKeys } from './featureRegistry.js'
|
||||
import { zustimmungFuerSitzung } from './featureConsents.js'
|
||||
import { createFeatureTicket } from './ticketAdmin.js'
|
||||
|
||||
export const FEATURE_KEYS = featureKeys()
|
||||
@@ -187,9 +188,26 @@ export async function backfillInvoiceLinks(customerId) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeitpunkt des Vertragsschlusses einer bezahlten Funktion (Anker der Widerrufsfrist): Zeit des Klicks aus dem Nachweis
|
||||
* zur bezahlten Stripe-Sitzung, sonst das Zustimmungsdatum am Dokument (Altbestand), sonst orderedAt. Eine spaetere,
|
||||
* unbezahlte Zustimmung (andere Sitzung) zaehlt nie. Die Widerrufspruefung darf an der Nachweis-Collection nicht
|
||||
* scheitern: ein Lesefehler faellt auf orderedAt zurueck (mit Log).
|
||||
*/
|
||||
async function vertragAt(doc) {
|
||||
try {
|
||||
const nachweis = await zustimmungFuerSitzung(doc.stripeSessionId)
|
||||
if (nachweis?.acceptedAt) return nachweis.acceptedAt
|
||||
} catch (err) {
|
||||
console.warn(`[funktionen] Zustimmungsnachweis zu Sitzung ${doc.stripeSessionId} nicht lesbar, Fristanker ist orderedAt:`, err.message)
|
||||
return doc.orderedAt || ''
|
||||
}
|
||||
return doc.consentAt || doc.orderedAt || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Bezahlte Funktionen eines Kunden mit Projektname und Ticketnummer (Widerruf der Funktion, Team-Hinweis T09).
|
||||
* Reine Lesefunktion; 'ordered' (noch nicht bezahlt) und 'off' zaehlen nicht.
|
||||
* Reine Lesefunktion; 'ordered' (noch nicht bezahlt) und 'off' zaehlen nicht. vertragAt ist der Anker der Widerrufsfrist.
|
||||
*/
|
||||
export async function paidFeatureOrders(customerId) {
|
||||
const docs = await listDocuments(config.collections.portalFeatures, [
|
||||
@@ -200,9 +218,11 @@ export async function paidFeatureOrders(customerId) {
|
||||
const result = []
|
||||
for (const doc of paid) {
|
||||
result.push({
|
||||
featureKey: doc.featureKey || '',
|
||||
projekt: await projectName(doc.projectId).catch(() => ''),
|
||||
state: doc.state,
|
||||
orderedAt: doc.orderedAt || '',
|
||||
vertragAt: await vertragAt(doc),
|
||||
ticketWoid: doc.ticketId ? await ticketWoid(doc.ticketId).catch(() => null) : null,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user