diff --git a/server/services/siteFeatures.js b/server/services/siteFeatures.js index 16d1db8..7b15d97 100644 --- a/server/services/siteFeatures.js +++ b/server/services/siteFeatures.js @@ -470,9 +470,22 @@ export async function disable(docId, { by, adminNote, reason = 'team' } = {}) { }) }) if (doc?.featureKey === 'analyse' && doc.siteKey) await stopAnalyseCollecting(doc) + if (doc?.featureKey === 'shop' && doc.siteKey) await leereShopCache(doc.siteKey) return doc } +// Shop abgeschaltet (auch ueber disableCustomerFeatures): der Kontext-Cache der oeffentlichen Schnittstelle haelt den Zustand bis zu +// 30 Sekunden, solange wuerden noch Bestellungen angenommen. Best effort, der Zustand ist schon gespeichert. +// Dynamischer Import: shop/kontext.js importiert dieses Modul. +async function leereShopCache(siteKey) { + try { + const { leereCache } = await import('./shop/kontext.js') + leereCache(siteKey) + } catch (err) { + console.warn('[siteFeatures] Shop-Cache nicht geleert:', err.message) + } +} + /** * Alle noch nicht abgeschalteten Dokumente einer Funktion eines Kunden abschalten (Kunde wird geloescht). Schon abgeschaltete * behalten ihr disabledAt (Beginn der Loeschfrist), 'off' hat nichts zu sperren. Scheitert eines, werden die uebrigen trotzdem diff --git a/test/siteFeatures.test.js b/test/siteFeatures.test.js index 9f62b5f..662007a 100644 --- a/test/siteFeatures.test.js +++ b/test/siteFeatures.test.js @@ -736,3 +736,29 @@ test('featureView: nach disable() steht der Grund in der Ansicht und die Frist i const danach = (await sf.listCustomerFeatures('c_e2')).find((p) => p.projectId === 'p_e2_live').features.termine assert.deepEqual([danach.disabledReason, danach.disabledAt, danach.loeschungAm], [null, null, null], 'Wiedereinschalten leert die Anzeige') }) + +// ------------------------------------------------ Shop: Kontext-Cache nach dem Abschalten (Review A, M10) --- + +test('M10: disable und disableCustomerFeatures leeren den Kontext-Cache des Shops (kein Annehmen von Bestellungen bis zu 30 s nach dem Abschalten)', async () => { + const K = await import('../server/services/shop/kontext.js') + const feature = (id, siteKey, projectId) => ({ $id: id, customerId: 'c1', projectId, featureKey: 'shop', siteKey, state: 'active', enabled: true }) + const shopDoc = (id, siteKey, projectId) => ({ $id: id, customerId: 'c1', projectId, siteKey, anfrageStatus: 'angenommen', geoeffnet: true, version: 1 }) + aw.seed('portalFeatures', feature('f_m10_a', 'abcdefghijklmnop', 'p1')) + aw.seed('shopConfig', shopDoc('f_m10_a', 'abcdefghijklmnop', 'p1')) + aw.seed('portalFeatures', feature('f_m10_b', 'bcdefghijklmnopq', 'p2')) + aw.seed('shopConfig', shopDoc('f_m10_b', 'bcdefghijklmnopq', 'p2')) + K.leereCache() + + assert.equal((await K.shopPerSiteKey('abcdefghijklmnop')).doc.state, 'active') + await sf.disable('f_m10_a', { by: 'kenso' }) + assert.equal((await K.shopPerSiteKey('abcdefghijklmnop')).doc.state, 'disabled') + + assert.equal((await K.shopPerSiteKey('bcdefghijklmnopq')).doc.state, 'active') + await sf.disableCustomerFeatures('c1', 'shop', { adminNote: 'Kunde gelöscht' }) + assert.equal((await K.shopPerSiteKey('bcdefghijklmnopq')).doc.state, 'disabled') + for (const id of ['f_m10_a', 'f_m10_b']) { + aw.docs('portalFeatures').delete(id) + aw.docs('shopConfig').delete(id) + } + K.leereCache() +})