-- 0029_delivery_contact_sources.sql -- -- Belegspezifische Kontaktdaten-Snapshots. ERPframe modelliert pro Beleg bis -- zu fünf Adressen (Belegadresse `Belegkopf.AdressId`, Lieferadresse -- `LieferAdressId`, Rechnungsadresse `RechnungsAdressId`, Ansprechpartner -- `AnsprechpartnerId`, plus die Kundenstamm-Adresse über `Kunden.AdressId`). -- Jeder dieser Adress-Datensätze trägt seinerseits mehrere Telefon-, -- Mobil- und E-Mail-Spalten (`Telefon..Telefon4`, `Mobiltel..Mobiltel2`, -- `EMail..EMail3`, `InternetAdresse`) sowie einen Namensblock -- (`Anrede`/`Titel`/`Name1..3`/`Abteilung`/`Funktion`). -- -- Wir spiegeln das als zwei Tabellen: pro Lieferung 0..n -- `delivery_contact_sources` (eine Zeile je Rolle), und pro Source 0..n -- `delivery_contact_channels` (eine Zeile je Telefon-/Mobil-/E-Mail-/Web- -- Eintrag). Snapshot-Semantik wie bei `deliveries.snap_*`: beim Sync werden -- alle Sources einer Lieferung gelöscht und neu geschrieben — die Lieferung -- behält damit den Stand vom letzten Sync, unabhängig von späteren ERP- -- Adressänderungen. -- -- `Fax` wird bewusst nicht gespiegelt (in der App nicht benutzt). CREATE TABLE delivery_contact_sources ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), delivery_id UUID NOT NULL REFERENCES deliveries(id) ON DELETE CASCADE, -- Mapping auf die ERP-FKs am Belegkopf bzw. den Kunden-Umweg: -- header → Belegkopf.AdressId -- delivery → Belegkopf.LieferAdressId -- billing → Belegkopf.RechnungsAdressId -- contact_person → Belegkopf.AnsprechpartnerId -- customer_master → Kunden.AdressId (über Belegkopf.KundenId) role TEXT NOT NULL CHECK (role IN ('header','delivery','billing', 'contact_person','customer_master')), anrede TEXT, titel TEXT, name1 TEXT, name2 TEXT, name3 TEXT, abteilung TEXT, funktion TEXT, UNIQUE (delivery_id, role) ); CREATE INDEX delivery_contact_sources_delivery ON delivery_contact_sources(delivery_id); CREATE TABLE delivery_contact_channels ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), source_id UUID NOT NULL REFERENCES delivery_contact_sources(id) ON DELETE CASCADE, -- phone → Adressen.Telefon{,2,3,4} -- mobile → Adressen.Mobiltel{,2} -- email → Adressen.EMail{,2,3} -- web → Adressen.InternetAdresse kind TEXT NOT NULL CHECK (kind IN ('phone','mobile','email','web')), -- 1-basierte Position aus dem ERP-Spaltennamen (Telefon → 1, Telefon2 → 2, -- usw.). Erlaubt der App, „primären" Kanal je Kind stabil zu erkennen. position SMALLINT NOT NULL CHECK (position >= 1), value TEXT NOT NULL CHECK (value <> ''), UNIQUE (source_id, kind, position) ); CREATE INDEX delivery_contact_channels_source ON delivery_contact_channels(source_id);