89 lines
4.0 KiB
JavaScript
89 lines
4.0 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Kundenansicht neu (Paket P5, Abo-Modell Kern): legt die neuen Attribute an. Der Code schreibt sie nur, wenn ein
|
||
* Aufrufer die zugehoerigen Parameter uebergibt; ohne dieses Skript bleibt die alte Ansicht unberuehrt.
|
||
* - featureConsents.kundenart: Kundenart zum Klickzeitpunkt im Nachweis ('privat' | 'unternehmen')
|
||
* - workorders.einrichtungFuer: Schluessel der Funktion, die das Einrichtungs-Ticket betrifft (laengster: 'unterkunft')
|
||
* - workorders.einrichtungAbrechnung: 'abo' | 'projekt' | '' (Abrechnung der Einrichtung am Ticket)
|
||
* - portalFeatures.einrichtungAbrechnung: dieselbe Abrechnung am Funktionsdokument (Nachlegen und Heilen setzen
|
||
* den Marker am Ticket erneut)
|
||
* - portalFeatures.unlockedBy: 'kauf' | 'abo' | 'team' | 'projekt' (steht schon im Zeiten-Schema; fehlt es, legt
|
||
* dieses Skript es an)
|
||
* Idempotent: Vorhandenes wird uebersprungen. Das Skript loescht nichts und laeuft in Entwicklung und Tests nie
|
||
* gegen Produktion; dort nur auf Anweisung des Controllers nach OK des Inhabers, vorher immer mit --pruefen.
|
||
* scripts/setup-abo-collections.mjs, feature-setup.mjs und zeiten-setup.mjs bleiben unveraendert.
|
||
* Usage:
|
||
* node scripts/kundenansicht-setup.mjs --pruefen (Alias --check; nur melden, nichts anlegen; Exit 1 bei Luecken)
|
||
* node scripts/kundenansicht-setup.mjs (Fehlendes anlegen)
|
||
*
|
||
* config.js und der Appwrite-Client werden erst in main() geladen: test/support/schema.js importiert die
|
||
* Attributlisten, bevor die Tests ihre Umgebung (useTestEnv) setzen koennen.
|
||
*/
|
||
import { pathToFileURL } from 'node:url'
|
||
import { ZEITEN_FEATURE_ATTRIBUTES } from '../server/services/zeiten/schema.js'
|
||
|
||
const str = (key, size) => ({ key, type: 'string', size, required: false })
|
||
const unlockedBy = ZEITEN_FEATURE_ATTRIBUTES.find((a) => a.key === 'unlockedBy')
|
||
|
||
export const KUNDENANSICHT_ATTRIBUTE = {
|
||
featureConsents: [str('kundenart', 12)],
|
||
workorders: [str('einrichtungFuer', 16), str('einrichtungAbrechnung', 8)],
|
||
portalFeatures: [unlockedBy, str('einrichtungAbrechnung', 8)],
|
||
}
|
||
|
||
export async function main({ pruefen = false, client, log = console.log } = {}) {
|
||
const { config } = await import('../server/config.js')
|
||
let api = client
|
||
if (!api) {
|
||
const { createAppwriteClient } = await import('./analyse-setup.mjs')
|
||
api = createAppwriteClient()
|
||
}
|
||
const missing = []
|
||
const plan = []
|
||
|
||
// Erst alles pruefen, dann (ohne --pruefen) anlegen, damit --pruefen garantiert nichts veraendert
|
||
for (const [name, attributes] of Object.entries(KUNDENANSICHT_ATTRIBUTE)) {
|
||
const id = config.collections[name]
|
||
const exists = await api.collectionExists(id)
|
||
if (!exists && !pruefen) throw new Error(`Collection ${id} fehlt – zuerst das jeweilige Setup-Skript ausfuehren`)
|
||
if (!exists) log(`- ${id} FEHLT`)
|
||
const have = exists ? new Set((await api.listAttributes(id)).map((a) => a.key)) : new Set()
|
||
for (const attr of attributes) {
|
||
if (have.has(attr.key)) log(`= ${id}.${attr.key} (existiert)`)
|
||
else if (pruefen) log(`- ${id}.${attr.key} FEHLT`)
|
||
}
|
||
const absent = attributes.filter((a) => !have.has(a.key))
|
||
absent.forEach((a) => missing.push({ ...a, collection: id }))
|
||
plan.push({ id, absent })
|
||
}
|
||
|
||
const result = { missing }
|
||
if (pruefen) {
|
||
log(missing.length ? `${missing.length} Eintrag/Eintraege fehlen.` : 'Alles vorhanden.')
|
||
return result
|
||
}
|
||
|
||
for (const { id, absent } of plan) {
|
||
for (const attr of absent) {
|
||
await api.createAttribute(id, attr)
|
||
log(`+ Attribut ${id}.${attr.key}`)
|
||
}
|
||
}
|
||
for (const { id, absent } of plan) {
|
||
for (const attr of absent) await api.waitForAttribute(id, attr.key)
|
||
}
|
||
log('Fertig.')
|
||
return result
|
||
}
|
||
|
||
const invokedDirectly = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href
|
||
if (invokedDirectly) {
|
||
const pruefen = process.argv.includes('--pruefen') || process.argv.includes('--check')
|
||
main({ pruefen })
|
||
.then(({ missing }) => process.exit(pruefen && missing.length ? 1 : 0))
|
||
.catch((e) => {
|
||
console.error(e.message)
|
||
process.exit(1)
|
||
})
|
||
}
|