Öffnungszeiten: Abo-Abgleich mit 30 Tagen Frist
gleicheZeitenAboAb(now) koppelt die im Wartungs-Abo enthaltenen Zeiten (unlockedBy abo) an das Abo (Spec 5, Z11): Abo-Ende erkennen (aboEndeAt, K26), nach 30 Berliner Kalendertagen abschalten (abo_ende, K27, Ersatz-Ticket), bei Rückkehr des Abos wieder einschalten (Neubau nach dem Abschalten, K24 wieder), 30 Tage nach dem Abschalten Daten löschen und state off. Lesefehler beim Abo: Kunde überspringen, nie abschalten oder löschen. R25: activate() leert aboEndeAt und behaltenSessionId; starteBehalten lehnt bei laufendem Wartungs-Abo mit 409 ab (Lesefehler 503). R17: k24Mail mit einbau null und wieder schaltet beide Einbau-Blöcke ab, K24 bekommt dafür den Block weiter um den Kasten "Wie geht es weiter?". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
53253f0451
commit
efc6dcf332
8 files changed
+1285
-10
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { config } from '../../config.js'
|
||||
import { aboLage } from '../aboStatus.js'
|
||||
import { getDocument, updateDocument } from '../appwriteAdmin.js'
|
||||
import { featureConfig } from '../featureRegistry.js'
|
||||
import { withLocks } from '../keyedLock.js'
|
||||
@@ -29,6 +30,8 @@ const KEY = 'zeiten'
|
||||
const konflikt = (text) => Object.assign(new Error(text), { status: 409 })
|
||||
|
||||
const NICHT_MOEGLICH = 'Behalten ist gerade nicht möglich. Das geht nur nach dem Ende deines Wartungs-Abos, solange deine Öffnungszeiten noch nicht gelöscht sind.'
|
||||
const ABO_LAEUFT = 'Dein Wartungs-Abo läuft wieder – Öffnungszeiten live ist darin enthalten.'
|
||||
const ABO_NICHT_PRUEFBAR = 'Gerade nicht prüfbar – bitte versuch es gleich noch einmal.'
|
||||
const ZAHLUNG_LAEUFT = 'Deine Zahlung wird gerade bestätigt. Bitte schau in einigen Minuten noch einmal vorbei.'
|
||||
const STRIPE_NICHT_ERREICHBAR = 'Die Zahlungsseite ist gerade nicht erreichbar. Bitte versuch es gleich noch einmal.'
|
||||
|
||||
@@ -48,6 +51,22 @@ async function behaltenMoeglich(doc) {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Läuft das Wartungs-Abo wieder, ist die Funktion darin enthalten und der Abo-Abgleich nimmt das Abo-Ende zurück (zeiten/aboAbgleich.js):
|
||||
* in der Zeit dazwischen soll niemand 30 € für etwas bezahlen, das ohnehin enthalten ist (Ruling R25). Frisch gelesen (aboLage direkt, nie
|
||||
* ein Zwischenspeicher); ein Lesefehler ist 503 (fail-closed: unklar, ob das Abo läuft), im Log stehen nur Art und Status.
|
||||
*/
|
||||
async function pruefeAboLaeuftNicht(customerId) {
|
||||
let lage
|
||||
try {
|
||||
lage = await aboLage(customerId)
|
||||
} catch (err) {
|
||||
console.error(`[zeiten] Behalten: Wartungs-Abo nicht lesbar: ${err?.name ?? 'Fehler'} ${err?.status ?? ''}`.trim())
|
||||
throw Object.assign(new Error(ABO_NICHT_PRUEFBAR), { status: 503 })
|
||||
}
|
||||
if (lage.laeuft === true) throw konflikt(ABO_LAEUFT)
|
||||
}
|
||||
|
||||
/** Die gespeicherte Behalten-Sitzung bei Stripe: offen => { url }; abgelaufen oder unbekannt => null (neue Sitzung); sonst 409 bzw. 503. */
|
||||
async function offeneSitzung(sessionId) {
|
||||
let session
|
||||
@@ -73,7 +92,7 @@ async function offeneSitzung(sessionId) {
|
||||
* @param {{ customer: { $id: string }, projectId: string, nachweis: (sessionId: string) => Promise<unknown>, now?: Date }} p
|
||||
* customer: Kundendokument; nachweis: speichert den Zustimmungsnachweis zur Stripe-Sitzung; now: Zeit des Klicks (Metadaten consentAt)
|
||||
* @returns {Promise<{ url: string }>}
|
||||
* @throws {Error} 409 (nicht moeglich, Zahlung laeuft), 503 (Stripe nicht erreichbar), sonst Fehler von Appwrite, Stripe und Nachweis
|
||||
* @throws {Error} 409 (nicht moeglich, Wartungs-Abo laeuft wieder, Zahlung laeuft), 503 (Abo oder Stripe nicht erreichbar), sonst Fehler von Appwrite, Stripe und Nachweis
|
||||
*/
|
||||
export async function starteBehalten({ customer, projectId, nachweis, now = new Date() } = {}) {
|
||||
if (typeof customer?.$id !== 'string' || customer.$id === '') throw new TypeError('starteBehalten: customer fehlt')
|
||||
@@ -84,6 +103,8 @@ export async function starteBehalten({ customer, projectId, nachweis, now = new
|
||||
return withLocks([`feature-order:${customerId}:${projectId}`], async () => {
|
||||
const doc = await getFeatureDoc(customerId, projectId, KEY)
|
||||
if (!(await behaltenMoeglich(doc))) throw konflikt(NICHT_MOEGLICH)
|
||||
// läuft das Abo wieder (der Abgleich hat das Abo-Ende noch nicht zurückgenommen), gibt es weder eine neue noch die alte Zahlungsseite
|
||||
await pruefeAboLaeuftNicht(customerId)
|
||||
|
||||
// eine schon begonnene Zahlung: dieselbe Seite nochmal, nie eine zweite Sitzung daneben
|
||||
if (doc.behaltenSessionId) {
|
||||
|
||||
Reference in new issue
Block a user