diff --git a/server/services/aboFunktionen.js b/server/services/aboFunktionen.js index 519e106..2c645e0 100644 --- a/server/services/aboFunktionen.js +++ b/server/services/aboFunktionen.js @@ -2,7 +2,7 @@ import { config } from '../config.js' import { getDocument } from './appwriteAdmin.js' import { ACTIVE_STATUSES, getCurrentSubscription } from './stripeBilling.js' import { listContractEvents, openWithdrawals } from './contractEvents.js' -import { neueAnsichtFuerKunde } from './kundenansicht/schalter.js' +import { neueAnsichtFuerKunde, neueAnsichtModus } from './kundenansicht/schalter.js' /** * Abo-Zuordnung der Funktionen (V5, Spec E3/E8): Welches Abo deckt welche Funktion? Ein Lesepfad (lies) fuer alle @@ -98,6 +98,9 @@ export async function aboLaeuftFuer(customerId, key) { */ export async function aboModellFuerKunde(customerId) { if (typeof customerId !== 'string' || customerId === '') return false + // Modus off: sofort false, ohne das Kundendokument zu lesen (E-Fix M2). Alt-Kunden bekommen so keine zusätzliche Lesung und keinen neuen Fehlerpfad + // (ein transienter Lesefehler liess die Beenden-Mail beim Widerruf des Wechsels und die Team-Aktivierung scheitern). + if (neueAnsichtModus() === 'off') return false let kunde try { kunde = await getDocument(config.collections.customers, customerId) diff --git a/test/analyseAboModell.test.js b/test/analyseAboModell.test.js index b31098b..b325029 100644 --- a/test/analyseAboModell.test.js +++ b/test/analyseAboModell.test.js @@ -198,3 +198,24 @@ test('Tagesprüfung: Hosting-Analyse bleibt für Kunden der neuen Ansicht, sonst assert.equal(await aboModellFuerKunde('gibtEsNicht'), false) // kein Kundendokument: kein Abo-Modell assert.equal(await aboModellFuerKunde(''), false) }) + +test('M2: aboModellFuerKunde liest bei Modus off kein Kundendokument (keine zusätzliche Lesung, kein neuer Fehlerpfad für Alt-Kunden)', async () => { + const vorher = { mode: config.kundenansichtNeu.mode, pilotEmails: [...config.kundenansichtNeu.pilotEmails] } + try { + Object.assign(config.kundenansichtNeu, { mode: 'off', pilotEmails: ['*'] }) + // ein transienter Lesefehler (503) trifft im Modus off nie: es wird gar nicht gelesen, die Antwort ist sofort false + aw.failNext({ collection: 'customers', method: 'GET', status: 503 }) + assert.equal(await aboModellFuerKunde('c1'), false) + // der eingeplante Fehler ist nicht verbraucht: die erste Lesung im Pilot trifft ihn (Lesefehler werden weitergereicht) + Object.assign(config.kundenansichtNeu, { mode: 'pilot', pilotEmails: ['k@example.invalid'] }) + await assert.rejects(() => aboModellFuerKunde('c1'), (err) => err.status === 500 && err.code === 503) // adminFetch macht aus jedem 5xx den Status 500, code bleibt 503 + // danach wie bisher: Pilot und on lesen das Kundendokument (kein Dokument: false) + assert.equal(await aboModellFuerKunde('c1'), true) + assert.equal(await aboModellFuerKunde('gibtEsNicht'), false) + Object.assign(config.kundenansichtNeu, { mode: 'on', pilotEmails: [] }) + assert.equal(await aboModellFuerKunde('c1'), true) + assert.equal(await aboModellFuerKunde('gibtEsNicht'), false) + } finally { + Object.assign(config.kundenansichtNeu, vorher) + } +})