Terminplaner-Banner und Meldung nach Abschaltgrund mit Löschdatum
GET /api/termine/einstellungen liefert bei abgeschalteter Funktion
abgeschaltet { grund, seit, loeschungAm }. Die 409-Meldung bei
Schreibversuchen (Code abgeschaltet) und der Banner im Portal
unterscheiden Wartungs-Abo beendet, Abo vor der Einrichtung beendet und
die übrigen Gründe und nennen das Löschdatum, wenn es eines gibt.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d66dd60a76
commit
36b36bcc4d
7 files changed
+268
-26
No files matched your search
+97
-11
@@ -1102,10 +1102,29 @@ test('exportSeite: ohne Funktion, mit ungueltigem Cursor oder ungueltiger Grenze
|
||||
|
||||
// ---------------------------------------------------------------- Abgeschaltet (disabled)
|
||||
|
||||
test('abgeschaltete Funktion: Lesen und Export gehen, jedes Schreiben ist 409', async () => {
|
||||
const disabled = featureDoc({ $id: 'f_p4_termine', projectId: 'p4', state: 'disabled', enabled: false, siteKey: 'cdefghijklmnopqr' })
|
||||
const MELDUNG_ALT = 'Der Terminplaner ist für diese Website abgeschaltet. Du kannst Termine nur noch ansehen und exportieren.'
|
||||
|
||||
/** Jede Schreib-Route des Portals, wie sie bei einer abgeschalteten Funktion von Projekt `projectId` aufgerufen wird. */
|
||||
const schreibVersuche = (projectId, einstellung) => [
|
||||
['PATCH', '/api/termine/einstellungen', { projectId, version: 1, einstellung }],
|
||||
['POST', '/api/termine/einstellungen/vorlage', { projectId, vorlage: 'salon' }],
|
||||
['POST', '/api/termine/buchungen', { ...manuellBody(), projectId }],
|
||||
['POST', '/api/termine/buchungen/b_alt/aktion', { projectId, aktion: 'absagen', grund: 'x' }],
|
||||
['POST', `/api/termine/ressourcen/${R1}/feed`, { projectId }],
|
||||
['DELETE', `/api/termine/buchungen/b_alt?projectId=${projectId}`],
|
||||
]
|
||||
|
||||
/** Funktion von p4 abgeschaltet mit Einstellung und einer Buchung; `over` setzt Grund und Zeitpunkt. */
|
||||
async function seedAbgeschaltet(over = {}) {
|
||||
const disabled = featureDoc({ $id: 'f_p4_termine', projectId: 'p4', state: 'disabled', enabled: false, siteKey: 'cdefghijklmnopqr', ...over })
|
||||
aw.seed('portalFeatures', disabled)
|
||||
await speichere(einstellung(), disabled)
|
||||
aw.seed('termineBookings', buchungsDoc('b_alt', { featureId: 'f_p4_termine', projectId: 'p4' }))
|
||||
return disabled
|
||||
}
|
||||
|
||||
test('abgeschaltete Funktion: Lesen und Export gehen, jedes Schreiben ist 409', async () => {
|
||||
await seedAbgeschaltet()
|
||||
const lesen = await send('GET', einstellungenUrl('p4'), { cookie })
|
||||
assert.equal(lesen.status, 200)
|
||||
assert.equal(lesen.body.state, 'disabled')
|
||||
@@ -1117,15 +1136,7 @@ test('abgeschaltete Funktion: Lesen und Export gehen, jedes Schreiben ist 409',
|
||||
assert.ok(export_.text.includes('Max Mustermann'))
|
||||
assert.equal((await send('GET', `/api/termine/zeiten?projectId=p4&leistung=${S_SOFORT}&tag=${TAG}`, { cookie })).status, 200)
|
||||
|
||||
const schreiben = [
|
||||
['PATCH', '/api/termine/einstellungen', { projectId: 'p4', version: 1, einstellung: lesen.body.einstellung }],
|
||||
['POST', '/api/termine/einstellungen/vorlage', { projectId: 'p4', vorlage: 'salon' }],
|
||||
['POST', '/api/termine/buchungen', { ...manuellBody(), projectId: 'p4' }],
|
||||
['POST', '/api/termine/buchungen/b_alt/aktion', { projectId: 'p4', aktion: 'absagen', grund: 'x' }],
|
||||
['POST', `/api/termine/ressourcen/${R1}/feed`, { projectId: 'p4' }],
|
||||
['DELETE', '/api/termine/buchungen/b_alt?projectId=p4'],
|
||||
]
|
||||
for (const [method, pfad, body] of schreiben) {
|
||||
for (const [method, pfad, body] of schreibVersuche('p4', lesen.body.einstellung)) {
|
||||
const res = await send(method, pfad, { cookie, body })
|
||||
assert.equal(res.status, 409, `${method} ${pfad}`)
|
||||
assert.equal(res.body.code, 'abgeschaltet')
|
||||
@@ -1134,6 +1145,81 @@ test('abgeschaltete Funktion: Lesen und Export gehen, jedes Schreiben ist 409',
|
||||
assert.equal(aw.docs('termineConfig').get('f_p4_termine').version, 1)
|
||||
})
|
||||
|
||||
test('abgeschaltet ohne Grund und Zeitpunkt (Altbestand): abgeschaltet leer, die Meldung bleibt der bisherige Satz', async () => {
|
||||
await seedAbgeschaltet()
|
||||
const lesen = await send('GET', einstellungenUrl('p4'), { cookie })
|
||||
assert.deepEqual(lesen.body.abgeschaltet, { grund: null, seit: null, loeschungAm: null })
|
||||
for (const [method, pfad, body] of schreibVersuche('p4', lesen.body.einstellung)) {
|
||||
const res = await send(method, pfad, { cookie, body })
|
||||
assert.equal(res.status, 409, `${method} ${pfad}`)
|
||||
assert.equal(res.body.code, 'abgeschaltet')
|
||||
assert.equal(res.body.error, MELDUNG_ALT, `${method} ${pfad}`)
|
||||
}
|
||||
})
|
||||
|
||||
test('abgeschaltet wegen Abo-Ende: Grund, Löschtag und Meldung mit Wartungs-Abo und Datum; Lesen und Export gehen weiter', async () => {
|
||||
await seedAbgeschaltet({ disabledReason: 'abo_ende', disabledAt: '2026-10-04T23:30:00.000Z' })
|
||||
const lesen = await send('GET', einstellungenUrl('p4'), { cookie })
|
||||
assert.equal(lesen.status, 200)
|
||||
// 23:30 UTC am 4.10. + 30 Tage = 3.11. 23:30 UTC = 4.11. 00:30 Berliner Zeit (Winterzeit)
|
||||
assert.deepEqual(lesen.body.abgeschaltet, { grund: 'abo_ende', seit: '2026-10-04T23:30:00.000Z', loeschungAm: '2026-11-04' })
|
||||
assert.equal((await send('GET', `/api/termine/buchungen?projectId=p4&von=${TAG}&bis=${TAG}`, { cookie })).status, 200)
|
||||
assert.equal((await rohExport('p4')).res.status, 200)
|
||||
for (const [method, pfad, body] of schreibVersuche('p4', lesen.body.einstellung)) {
|
||||
const res = await send(method, pfad, { cookie, body })
|
||||
assert.equal(res.status, 409, `${method} ${pfad}`)
|
||||
assert.equal(res.body.code, 'abgeschaltet')
|
||||
assert.ok(res.body.error.includes('Wartungs-Abo') && res.body.error.includes('04.11.2026'), `${method} ${pfad}: ${res.body.error}`)
|
||||
assert.equal(res.body.error, 'Der Terminplaner ist abgeschaltet, weil dein Wartungs-Abo beendet ist. Du kannst Termine nur noch ansehen und exportieren. Ab dem 04.11.2026 löschen wir die Daten.')
|
||||
}
|
||||
assert.equal(aw.docs('termineBookings').get('b_alt').status, 'bestaetigt')
|
||||
})
|
||||
|
||||
test('abgeschaltet, weil das Abo vor der Einrichtung endete: Meldung nennt "eingerichtet" und das Löschdatum', async () => {
|
||||
await seedAbgeschaltet({ disabledReason: 'abo_ende_vor_einrichtung', disabledAt: '2026-10-04T10:00:00.000Z' })
|
||||
const lesen = await send('GET', einstellungenUrl('p4'), { cookie })
|
||||
assert.deepEqual(lesen.body.abgeschaltet, { grund: 'abo_ende_vor_einrichtung', seit: '2026-10-04T10:00:00.000Z', loeschungAm: '2026-11-03' })
|
||||
for (const [method, pfad, body] of schreibVersuche('p4', lesen.body.einstellung)) {
|
||||
const res = await send(method, pfad, { cookie, body })
|
||||
assert.equal(res.status, 409, `${method} ${pfad}`)
|
||||
assert.equal(res.body.code, 'abgeschaltet')
|
||||
assert.ok(res.body.error.includes('eingerichtet') && res.body.error.includes('Wartungs-Abo endete'), `${method} ${pfad}: ${res.body.error}`)
|
||||
assert.ok(res.body.error.endsWith('Ab dem 03.11.2026 löschen wir die Daten.'), res.body.error)
|
||||
assert.ok(!/exportieren/.test(res.body.error), 'es gibt nichts zu exportieren')
|
||||
}
|
||||
})
|
||||
|
||||
test('abgeschaltet durch das Team oder wegen gelöschtem Konto: bisheriger Satz, mit Zeitpunkt zusätzlich das Löschdatum', async () => {
|
||||
for (const grund of ['team', 'kunde_geloescht']) {
|
||||
await seedAbgeschaltet({ disabledReason: grund, disabledAt: '2026-10-04T23:30:00.000Z' })
|
||||
const lesen = await send('GET', einstellungenUrl('p4'), { cookie })
|
||||
assert.deepEqual(lesen.body.abgeschaltet, { grund, seit: '2026-10-04T23:30:00.000Z', loeschungAm: '2026-11-04' })
|
||||
const res = await send('PATCH', '/api/termine/einstellungen', { cookie, body: { projectId: 'p4', version: 1, einstellung: lesen.body.einstellung } })
|
||||
assert.equal(res.status, 409, grund)
|
||||
assert.equal(res.body.code, 'abgeschaltet')
|
||||
assert.equal(res.body.error, `${MELDUNG_ALT} Ab dem 04.11.2026 löschen wir die Daten.`, grund)
|
||||
}
|
||||
})
|
||||
|
||||
test('abgeschaltet mit unlesbarem Zeitpunkt: Grund bleibt, Löschtag fehlt und die Meldung nennt kein Datum', async () => {
|
||||
await seedAbgeschaltet({ disabledReason: 'abo_ende', disabledAt: 'kein Datum' })
|
||||
const lesen = await send('GET', einstellungenUrl('p4'), { cookie })
|
||||
assert.deepEqual(lesen.body.abgeschaltet, { grund: 'abo_ende', seit: 'kein Datum', loeschungAm: null })
|
||||
const res = await send('PATCH', '/api/termine/einstellungen', { cookie, body: { projectId: 'p4', version: 1, einstellung: lesen.body.einstellung } })
|
||||
assert.equal(res.status, 409)
|
||||
assert.equal(res.body.error, 'Der Terminplaner ist abgeschaltet, weil dein Wartungs-Abo beendet ist. Du kannst Termine nur noch ansehen und exportieren.')
|
||||
})
|
||||
|
||||
test('aktive Funktion: abgeschaltet ist null, auch wenn am Dokument noch Reste einer früheren Abschaltung stehen', async () => {
|
||||
await speichere()
|
||||
assert.equal((await lade()).abgeschaltet, null)
|
||||
aw.seed('portalFeatures', featureDoc({ disabledReason: 'abo_ende', disabledAt: '2026-10-04T23:30:00.000Z' }))
|
||||
resetKontextForTests()
|
||||
const body = await lade()
|
||||
assert.equal(body.state, 'active')
|
||||
assert.equal(body.abgeschaltet, null)
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- Kundenansicht
|
||||
|
||||
test('Kundenansicht darf PATCH, POST und DELETE (mit Header) und es wird protokolliert; ohne Gastdaten im Protokoll', async () => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { test } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync, readdirSync } from 'node:fs'
|
||||
import {
|
||||
FILTER, ABSAGE_GRUENDE, anfragenText, bereichFuer, datumKurz, datumLang, endeZeit, fensterParsen, fensterText, filterStatus, gruppiereNachTag,
|
||||
FILTER, ABSAGE_GRUENDE, abschaltText, anfragenText, bereichFuer, datumKurz, datumLang, endeZeit, fensterParsen, fensterText, filterStatus, gruppiereNachTag,
|
||||
fehltText, fensterAufteilen, heuteBerlin, istSperre, istTag, monatVon, moeglicheAktionen, ressourcenWort, statusLabel, statusTon, tagPlus, tagUeberschrift, verschiebeTag, wocheVon, zeitNormal, zeitraumTitel,
|
||||
} from '../public/termine-view.js'
|
||||
import {
|
||||
@@ -252,6 +252,49 @@ test('fehltText: Pflichtangaben für Gäste in Worten', () => {
|
||||
})
|
||||
|
||||
// ---- Verdrahtung (Portal-Ansicht #termine)
|
||||
test('abschaltText: Text je Abschaltgrund, mit und ohne Löschdatum, Du-Form', () => {
|
||||
const alt = 'Der Terminplaner ist für diese Website abgeschaltet. Du kannst Termine nur noch ansehen und '
|
||||
const loeschen = ' Ab dem 04.11.2026 löschen wir die Daten.'
|
||||
// Abo beendet: Wartungs-Abo im Text, Export bleibt
|
||||
assert.deepEqual(abschaltText({ grund: 'abo_ende', loeschungAm: '2026-11-04' }), {
|
||||
davor: 'Der Terminplaner ist abgeschaltet, weil dein Wartungs-Abo beendet ist. Du kannst Termine nur noch ansehen und ',
|
||||
danach: `.${loeschen}`,
|
||||
mitExport: true,
|
||||
})
|
||||
assert.deepEqual(abschaltText({ grund: 'abo_ende', loeschungAm: null }), {
|
||||
davor: 'Der Terminplaner ist abgeschaltet, weil dein Wartungs-Abo beendet ist. Du kannst Termine nur noch ansehen und ',
|
||||
danach: '.',
|
||||
mitExport: true,
|
||||
})
|
||||
// Abo endete vor der Einrichtung: nichts zu exportieren, also kein Export-Satz
|
||||
const vor = abschaltText({ grund: 'abo_ende_vor_einrichtung', loeschungAm: '2026-11-04' })
|
||||
assert.equal(vor.mitExport, false)
|
||||
assert.equal(vor.davor + vor.danach, `Der Terminplaner ist abgeschaltet, weil dein Wartungs-Abo endete, bevor der Terminplaner eingerichtet war.${loeschen}`)
|
||||
const vorOhne = abschaltText({ grund: 'abo_ende_vor_einrichtung', loeschungAm: null })
|
||||
assert.equal(vorOhne.mitExport, false)
|
||||
assert.equal(vorOhne.davor + vorOhne.danach, 'Der Terminplaner ist abgeschaltet, weil dein Wartungs-Abo endete, bevor der Terminplaner eingerichtet war.')
|
||||
// Team, gelöschtes Konto, kein Grund (Altbestand), unbekannter Grund, fehlende Angabe: der bisherige Satz, mit Datum ergänzt
|
||||
for (const grund of ['team', 'kunde_geloescht', null, undefined, 'frist', 5]) {
|
||||
assert.deepEqual(abschaltText({ grund, loeschungAm: '2026-11-04' }), { davor: alt, danach: `.${loeschen}`, mitExport: true }, String(grund))
|
||||
assert.deepEqual(abschaltText({ grund, loeschungAm: null }), { davor: alt, danach: '.', mitExport: true }, String(grund))
|
||||
}
|
||||
assert.deepEqual(abschaltText(), { davor: alt, danach: '.', mitExport: true })
|
||||
assert.deepEqual(abschaltText(null), { davor: alt, danach: '.', mitExport: true })
|
||||
// mitExport ist nur bei vor_einrichtung falsch
|
||||
for (const grund of ['abo_ende', 'team', 'kunde_geloescht', null]) assert.equal(abschaltText({ grund }).mitExport, true, String(grund))
|
||||
})
|
||||
|
||||
test('abschaltText: ein Datum, das kein Berliner Kalendertag ist, wird nicht angezeigt; nie Sie/Ihr', () => {
|
||||
for (const kaputt of ['04.11.2026', '2026-13-45', '', 'morgen', 20261104, {}]) {
|
||||
const t = abschaltText({ grund: 'abo_ende', loeschungAm: kaputt })
|
||||
assert.ok(!/löschen/.test(t.davor + t.danach), `kein Datum für ${JSON.stringify(kaputt)}`)
|
||||
}
|
||||
for (const grund of ['abo_ende', 'abo_ende_vor_einrichtung', 'team', 'kunde_geloescht', null]) {
|
||||
const t = abschaltText({ grund, loeschungAm: '2026-11-04' })
|
||||
assert.doesNotMatch(t.davor + t.danach, /\bSie\b|\bIhr(e[nmrs]?)?\b/, String(grund))
|
||||
}
|
||||
})
|
||||
|
||||
const lies = (pfad) => readFileSync(new URL(`../${pfad}`, import.meta.url), 'utf8')
|
||||
|
||||
test('Portal: Ansicht #termine ist verdrahtet, funktionen.js lädt keine Terminplaner-Module', () => {
|
||||
|
||||
@@ -87,6 +87,7 @@ function neueFixture() {
|
||||
fx.daten = (state = fx.projekte[0].features.termine.state) => ({
|
||||
state, aktivSeit: '2026-10-01T09:00:00.000Z', einstellung: fx.einstellung, version: fx.einstellung ? 3 : 0, vorlagen: fx.vorlagen, feeds: {}, siteKey: KEY,
|
||||
einbau: { snippet: '' }, anfragenOffen: fx.buchungen.filter((b) => b.status === 'angefragt').length || fx.anfragenOffen, fehlt: fx.fehlt,
|
||||
abgeschaltet: state === 'disabled' ? fx.abgeschaltet ?? { grund: null, seit: null, loeschungAm: null } : null,
|
||||
})
|
||||
return fx
|
||||
}
|
||||
@@ -735,6 +736,49 @@ async function pruefungen() {
|
||||
})(),
|
||||
})
|
||||
|
||||
// ------------------------------------------------------------ Abgeschaltet nach Grund (E11)
|
||||
await check('fx_abgeschaltet_abo_ende', async (page) => {
|
||||
await oeffne(page, '#termine')
|
||||
await warteAnsicht(page)
|
||||
const hinweis = page.locator('.tm-box-warn')
|
||||
await hinweis.waitFor()
|
||||
const text = await textVon(hinweis)
|
||||
assert(text.includes('Wartungs-Abo') && text.includes('04.11.2026'), `Banner nennt Abo und Löschdatum: ${text}`)
|
||||
assert(text.includes('nur noch ansehen'), `Banner: ${text}`)
|
||||
eq(await page.locator('.tm-box-warn a').count(), 1, 'genau ein Link im Banner')
|
||||
eq(await page.locator('.tm-box-warn a').innerText(), 'exportieren', 'Linktext')
|
||||
eq(await page.locator('.tm-box-warn a').getAttribute('href'), '/api/termine/export.csv?projectId=p1', 'Export-Link')
|
||||
eq(await page.locator('[data-werkzeug]').count(), 0, 'keine Schreib-Knöpfe')
|
||||
await shot(page, 'fx-abgeschaltet-abo-ende')
|
||||
}, {
|
||||
fixture: (() => {
|
||||
const fx = neueFixture()
|
||||
fx.projekte[0].features.termine = { state: 'disabled' }
|
||||
fx.abgeschaltet = { grund: 'abo_ende', seit: '2026-10-04T23:30:00.000Z', loeschungAm: '2026-11-04' }
|
||||
return fx
|
||||
})(),
|
||||
})
|
||||
|
||||
await check('fx_abgeschaltet_vor_einrichtung', async (page) => {
|
||||
await oeffne(page, '#termine')
|
||||
await warteAnsicht(page)
|
||||
const hinweis = page.locator('.tm-box-warn')
|
||||
await hinweis.waitFor()
|
||||
const text = await textVon(hinweis)
|
||||
assert(text.includes('eingerichtet') && text.includes('Wartungs-Abo') && text.includes('04.11.2026'), `Banner: ${text}`)
|
||||
assert(!text.includes('exportieren'), `Banner ohne Export-Satz: ${text}`)
|
||||
eq(await hinweis.locator('a').count(), 0, 'kein Link: es gibt nichts zu exportieren')
|
||||
assert((await textVon(page.locator('.tm-info'))).includes('Keine Termine eingerichtet'), 'Info-Karte')
|
||||
}, {
|
||||
fixture: (() => {
|
||||
const fx = neueFixture()
|
||||
fx.projekte[0].features.termine = { state: 'disabled' }
|
||||
fx.einstellung = null
|
||||
fx.abgeschaltet = { grund: 'abo_ende_vor_einrichtung', seit: '2026-10-04T23:30:00.000Z', loeschungAm: '2026-11-04' }
|
||||
return fx
|
||||
})(),
|
||||
})
|
||||
|
||||
// ------------------------------------------------------------ Datumssprung mit Unsinn
|
||||
await check('fx_datumssprung_unsinn', async (page) => {
|
||||
await oeffne(page, '#termine')
|
||||
@@ -1037,6 +1081,7 @@ async function pruefungen() {
|
||||
await warteAnsicht(page)
|
||||
const hinweis = await textVon(page.locator('.tm-box-warn'))
|
||||
assert(hinweis.includes('abgeschaltet') && hinweis.includes('nur noch ansehen'), `Banner: ${hinweis}`)
|
||||
assert(!hinweis.includes('Wartungs-Abo') && !hinweis.includes('löschen'), `ohne Grund und Zeitpunkt der bisherige Satz: ${hinweis}`)
|
||||
eq(await page.locator('.tm-box-warn a').getAttribute('href'), '/api/termine/export.csv?projectId=p1', 'Export-Link')
|
||||
eq(await page.locator('[data-werkzeug]').count(), 0, 'keine Schreib-Knoepfe oben')
|
||||
await page.getByRole('button', { name: 'Tag', exact: true }).click()
|
||||
@@ -1049,6 +1094,28 @@ async function pruefungen() {
|
||||
eq(r, 409, 'Server: Schreiben bei abgeschalteter Funktion')
|
||||
})
|
||||
|
||||
await check('echt_abgeschaltet_abo_ende', async (page) => {
|
||||
await srv.setzeFunktion('disabled', { disabledReason: 'abo_ende', disabledAt: '2026-10-04T23:30:00.000Z' })
|
||||
await oeffne(page, '#termine')
|
||||
await warteAnsicht(page)
|
||||
const hinweis = page.locator('.tm-box-warn')
|
||||
await hinweis.waitFor()
|
||||
const text = await textVon(hinweis)
|
||||
assert(text.includes('Wartungs-Abo') && text.includes('04.11.2026'), `Banner nennt Abo und Löschdatum: ${text}`)
|
||||
eq(await page.locator('.tm-box-warn a').count(), 1, 'genau ein Link im Banner')
|
||||
eq(await page.locator('.tm-box-warn a').innerText(), 'exportieren', 'Linktext')
|
||||
eq(await page.locator('.tm-box-warn a').getAttribute('href'), '/api/termine/export.csv?projectId=p1', 'Export-Link')
|
||||
// die Schnittstelle nennt dasselbe beim Schreiben
|
||||
const antwort = await page.evaluate(async () => {
|
||||
const res = await fetch('/api/termine/buchungen/b_alt/aktion', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ projectId: 'p1', aktion: 'annehmen' }) })
|
||||
return { status: res.status, body: await res.json() }
|
||||
})
|
||||
eq(antwort.status, 409, 'Server: Schreiben bei abgeschalteter Funktion')
|
||||
eq(antwort.body.code, 'abgeschaltet', 'Code bleibt')
|
||||
assert(antwort.body.error.includes('Wartungs-Abo') && antwort.body.error.includes('04.11.2026'), `Meldung: ${antwort.body.error}`)
|
||||
await shot(page, 'echt-abgeschaltet-abo-ende')
|
||||
})
|
||||
|
||||
await check('echt_390_liste_und_formular', async (page) => {
|
||||
srv.aw.seed('termineBookings', {
|
||||
$id: 'b_390', featureId: srv.FEATURE, customerId: srv.KUNDE, projectId: srv.PROJEKT, leistungId: S_DAMEN, leistungName: 'Damenschnitt', ressourceId: R_ANNA, ressourceName: 'Anna',
|
||||
|
||||
@@ -188,13 +188,13 @@ export async function startTermineUiServer({ jetzt = JETZT, crossOrigin = false,
|
||||
setzeUhr(datum) { versatz = new Date(datum).getTime() - Date.now() },
|
||||
|
||||
/** Portal-Funktion des Termin-Features (portalFeatures-Dokument). */
|
||||
featureDoc(state = 'active') {
|
||||
return { $id: FEATURE, customerId: KUNDE, projectId: PROJEKT, featureKey: 'termine', state, enabled: state === 'active', siteKey: SITE_KEY, activatedAt: '2026-10-01T09:00:00.000Z' }
|
||||
featureDoc(state = 'active', extra = {}) {
|
||||
return { $id: FEATURE, customerId: KUNDE, projectId: PROJEKT, featureKey: 'termine', state, enabled: state === 'active', siteKey: SITE_KEY, activatedAt: '2026-10-01T09:00:00.000Z', ...extra }
|
||||
},
|
||||
|
||||
/** Zustand der Funktion aendern ('active' | 'disabled' | 'off'); der Kontext-Speicher des Servers wird geleert. */
|
||||
async setzeFunktion(state) {
|
||||
aw.seed('portalFeatures', srv.featureDoc(state))
|
||||
/** Zustand der Funktion aendern ('active' | 'disabled' | 'off'); extra: weitere Felder des Dokuments (z. B. disabledReason, disabledAt). Der Kontext-Speicher des Servers wird geleert. */
|
||||
async setzeFunktion(state, extra = {}) {
|
||||
aw.seed('portalFeatures', srv.featureDoc(state, extra))
|
||||
resetKontextForTests()
|
||||
},
|
||||
|
||||
|
||||
Reference in new issue
Block a user