/** * Buchungskalender: Appwrite-Schema der sechs Collections (Spezifikation 2026-10-07-buchungskalender-design.md, Abschnitt 3). * Reine Daten, absichtlich ohne Import von server/config.js (wie shop/schema.js: test/support/schema.js liest sie vor * useTestEnv()). Die Collection-IDs stehen in config.collections.; scripts/unterkunft-setup.mjs legt alles an. * Kein Feld heisst data; JSON-Felder sind Text. ukEinstellungen: Dokument-ID = featureId. * * Attribut: { key, type: 'string' | 'integer' | 'boolean' | 'datetime', size (nur Text), required: false } * Index: { key, type: 'key', attributes: [...] } * Datumswerte (dt) sind UTC (toISOString()); Kalendertage (von, bis, datum) sind Text YYYY-MM-DD (Berlin). */ const str = (key, size) => ({ key, type: 'string', size, required: false }) const int = (key) => ({ key, type: 'integer', required: false }) const bool = (key) => ({ key, type: 'boolean', required: false }) const dt = (key) => ({ key, type: 'datetime', required: false }) const index = (key, ...attributes) => ({ key, type: 'key', attributes }) export const UNTERKUNFT_COLLECTIONS = { ukUnterkuenfte: { attributes: [ str('featureId', 36), str('customerId', 36), str('projectId', 36), str('name', 120), str('beschreibung', 500), int('maxPersonen'), int('mindestNaechte'), str('checkIn', 5), str('checkOut', 5), int('sort'), bool('aktiv'), str('icalImporte', 8000), str('icalExportToken', 64), ], indexes: [index('idx_feature', 'featureId'), index('idx_export_token', 'icalExportToken')], }, ukPreise: { attributes: [ str('unterkunftId', 36), str('featureId', 36), str('staffeln', 2000), int('reinigungCent'), int('personenInklusive'), int('aufpreisPersonNachtCent'), int('direktrabattProzent'), str('steuerart', 20), int('ustUebernachtung'), int('ustReinigung'), int('fristTage'), str('stornobedingungen', 5000), ], indexes: [index('idx_unterkunft', 'unterkunftId')], }, ukSperren: { attributes: [ str('unterkunftId', 36), str('featureId', 36), str('von', 10), str('bis', 10), str('quelle', 60), str('notiz', 200), ], indexes: [index('idx_unterkunft', 'unterkunftId'), index('idx_unterkunft_quelle', 'unterkunftId', 'quelle'), index('idx_bis', 'bis')], }, ukAnfragen: { attributes: [ str('featureId', 36), str('customerId', 36), str('projectId', 36), str('unterkunftId', 36), str('nummer', 12), str('von', 10), str('bis', 10), int('personen'), str('status', 12), str('gast', 20000), str('rechnungsadresse', 1500), str('posten', 20000), str('summen', 1000), str('nachrichtVermieter', 2000), dt('fristAt'), str('tokenHash', 64), str('zahlart', 8), str('bezahltVia', 8), dt('bezahltAt'), str('stripeSessionId', 100), str('stripePaymentIntentId', 100), int('erstattetCent'), str('stornoGrund', 500), str('stornobedingungenText', 20000), str('rechtstexteFassung', 20), str('ipHash', 16), dt('freigegebenAt'), dt('gebuchtAt'), dt('abgelehntAt'), dt('abgelaufenAt'), dt('storniertAt'), str('rechnungId', 36), dt('anonymisiertAt'), ], indexes: [ index('idx_feature', 'featureId'), index('idx_unterkunft', 'unterkunftId'), index('idx_unterkunft_status', 'unterkunftId', 'status'), index('idx_status', 'status'), index('idx_bis', 'bis'), ], }, ukRechnungen: { attributes: [ str('featureId', 36), str('anfrageId', 36), str('art', 8), str('nummer', 24), str('datum', 10), int('bruttoCent'), str('inhalt', 20000), ], indexes: [index('idx_feature', 'featureId'), index('idx_anfrage', 'anfrageId'), { key: 'uniq_feature_nummer', type: 'unique', attributes: ['featureId', 'nummer'] }], }, ukEinstellungen: { attributes: [ str('featureId', 36), str('firma', 150), str('inhaber', 150), str('strasse', 150), str('plz', 10), str('ort', 100), str('email', 200), str('telefon', 50), str('steuernummer', 30), str('ustId', 20), str('iban', 34), str('bic', 11), str('bank', 100), str('rechnungsPraefix', 8), str('rechnungZaehler', 100), str('akzentfarbe', 7), str('stripeAccountId', 40), str('stripeStatus', 4000), bool('onlineZahlung'), dt('rechnungAuftragAt'), str('anfrage', 2000), str('anfrageStatus', 16), dt('anfrageAt'), dt('anfrageEntschiedenAt'), str('anfrageEntschiedenVon', 120), str('anfrageBegruendung', 1000), dt('icalFehlerMailAt'), ], // idx_account: account.updated des Connect-Webhooks findet die Einstellungen eines Kontos indexes: [index('idx_feature', 'featureId'), index('idx_account', 'stripeAccountId')], }, } /** Je Collection die datetime-Attribute (der Appwrite-Nachbau der Tests normalisiert sie). */ export const UNTERKUNFT_DATETIMES = Object.fromEntries( Object.entries(UNTERKUNFT_COLLECTIONS).map(([name, { attributes }]) => [name, attributes.filter((a) => a.type === 'datetime').map((a) => a.key)]), )