159 lines
5.2 KiB
JavaScript
159 lines
5.2 KiB
JavaScript
/**
|
|
* 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.<Name>; 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', 4000),
|
|
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')],
|
|
},
|
|
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', 3000),
|
|
str('rechnungsadresse', 1500),
|
|
str('posten', 8000),
|
|
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', 5000),
|
|
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'),
|
|
],
|
|
},
|
|
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'), index('idx_feature_nummer', '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)]),
|
|
)
|