import { config } from '../config.js' import { ENTHALTEN_IN } from './aboFunktionen.js' import { consentAbo, featureConfig, featureSperre, katalogFelder, katalogReihenfolge } from './featureRegistry.js' import { unterlagenFuer } from './aboUnterlagen.js' import { leseShopConfig } from './shop/anfrage.js' import { ladeEinstellungen } from './unterkunft/speicher.js' /** * Katalog der Funktionen im Abo-Modell (V5) fuer GET /api/funktionen mit neuer Ansicht. Reine Lesefunktionen; der Katalog enthaelt * keinen Preis. Alle Texte kommen vom Server (Register, config.aboFunktionen), nie vom Client. */ /** Oeffentliche Sicht der Erklaerung: version, knopf und die Items in Anzeigereihenfolge (nurPrivatInFrist nur, wo es gesetzt ist). */ function oeffentlicheErklaerung(consent) { if (!consent) return null return { version: consent.version, knopf: consent.knopf, items: consent.items.map((item) => ({ id: item.id, text: item.text, haken: Boolean(item.haken), ...(item.nurPrivatInFrist ? { nurPrivatInFrist: true } : {}), })), } } /** * Katalogeintraege in der Reihenfolge von katalogReihenfolge(); die Analyse nur bei config.analyse.enabled. * @param {{ email?: string }} p email: Konto des Kunden (Schalter und Pilotlisten der Funktionen) * @returns {Promise>} */ export async function katalogFuerKunde({ email } = {}) { const eintraege = [] for (const key of katalogReihenfolge()) { if (key === 'analyse' && !config.analyse.enabled) continue const felder = katalogFelder(key) const consent = oeffentlicheErklaerung(consentAbo(key)) // null bei analyse eintraege.push({ key, name: key === 'analyse' ? config.aboFunktionen.analyse.name : featureConfig(key).label.name, beschreibung: felder.beschreibung, bild: felder.bild, enthaltenIn: ENTHALTEN_IN[key][0], // das kleinste Abo, das die Funktion enthaelt verfuegbar: key === 'analyse' ? true : featureSperre(key, email) === null, ablauf: felder.ablauf, einrichtung: felder.einrichtung, unterlagen: unterlagenFuer(key), nurBetrieb: felder.nurBetrieb, consent, hinweis: consent?.items.find((item) => item.id === 'hinweis')?.text ?? null, }) } return eintraege } /** Anfragestatus einer Funktion zum Dokument: shopConfig (shop) bzw. ukEinstellungen (unterkunft). Lesefehler ergeben '' und einen Logeintrag. */ async function leseAnfrageStatus(key, doc) { if (!doc) return '' try { const gelesen = key === 'shop' ? await leseShopConfig(doc.$id) : await ladeEinstellungen(doc.$id) return typeof gelesen?.anfrageStatus === 'string' ? gelesen.anfrageStatus : '' } catch (err) { console.error(`[funktionen] Anfragestatus (${key}) nicht lesbar: ${err?.name ?? 'Fehler'} ${err?.status ?? ''}`.trim()) return '' } } /** * Anfragestatus von Webshop und Buchungskalender je Projekt: Map mit '' | 'offen' | 'angenommen' | * 'abgelehnt' | 'zurueckgezogen'. Je Projekt mit Funktionsdokument wird genau eine Konfiguration gelesen, ohne Dokument gilt ''. * @param {{ docs: object[], projects: Array<{ projectId: string }> }} p docs: portalFeatures-Dokumente des Kunden; projects: Projekte der Liste */ export async function anfrageStatusJeProjekt({ docs, projects }) { const ergebnis = new Map() await Promise.all( projects.map(async (projekt) => { const dokument = (key) => docs.find((d) => d.projectId === projekt.projectId && d.featureKey === key) const [shop, unterkunft] = await Promise.all([leseAnfrageStatus('shop', dokument('shop')), leseAnfrageStatus('unterkunft', dokument('unterkunft'))]) ergebnis.set(projekt.projectId, { shop, unterkunft }) }) ) return ergebnis }