Files
Webklar-Kundenbereich/server/services/aboKatalog.js
T

86 lines
3.9 KiB
JavaScript

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<Array<{ key: string, name: string, beschreibung: string, bild: string, enthaltenIn: 'hosting'|'wartung', verfuegbar: boolean,
* ablauf: string, einrichtung: string, unterlagen: object, nurBetrieb: boolean, consent: object|null, hinweis: string|null }>>}
*/
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<projectId, { shop, unterkunft }> 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
}