-- Migration: Widerrufs-Button nach EU-RL 2026/2673 (§ 312g BGB neu) -- Datum: 2026-04-19 -- Autor: Thomas Bartelt / Wlanium -- Scope: Elektronischer Widerruf für B2C (Endverbraucher=1, Gast=103) -- Silent-Modus bis Mitte Mai 2026 via Config-Flag (kein DB-Flag nötig) SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 1; -- ============================================================ -- Tabelle: revocations -- Ein Eintrag pro Bestellung, für die ein Widerrufs-Link erzeugt -- wurde. Legacy-Bestellungen vor Go-Live bleiben unberührt. -- ============================================================ CREATE TABLE IF NOT EXISTS revocations ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, order_id BIGINT UNSIGNED NOT NULL, customer_id INT UNSIGNED NULL, customer_email VARCHAR(255) NOT NULL, customer_group_id INT NOT NULL COMMENT 'Snapshot zum Bestellzeitpunkt', token_hash CHAR(64) NOT NULL COMMENT 'SHA-256 des URL-Tokens', expires_at DATETIME NOT NULL COMMENT '20 Tage ab Bestelldatum', status ENUM('pending','submitted','processed','expired','revoked_by_admin') NOT NULL DEFAULT 'pending', submitted_at DATETIME NULL, processed_at DATETIME NULL, owner_notified_at DATETIME NULL, customer_confirmed_at DATETIME NULL, reason_id INT UNSIGNED NULL, reason_text TEXT NULL, ip_anonymized VARCHAR(45) NULL COMMENT 'gesetzt nur bei submit, /24 v4 oder /48 v6', user_agent VARCHAR(255) NULL, admin_note TEXT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_token_hash (token_hash), UNIQUE KEY uk_order_id (order_id) COMMENT 'max 1 Widerruf pro Bestellung', KEY idx_status_expires (status, expires_at), KEY idx_customer_email (customer_email), CONSTRAINT fk_rev_order FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ============================================================ -- Tabelle: revocation_reasons -- Optionale Gründe-Liste für das Widerrufs-Formular. -- Bewusst eigene Tabelle, nicht cancellationreasons (andere Semantik). -- ============================================================ CREATE TABLE IF NOT EXISTS revocation_reasons ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, label VARCHAR(150) NOT NULL, sort SMALLINT UNSIGNED NOT NULL DEFAULT 0, active TINYINT(1) UNSIGNED NOT NULL DEFAULT 1, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Seed: 6 Standardgründe INSERT INTO revocation_reasons (label, sort, active) VALUES ('Artikel entspricht nicht der Beschreibung', 10, 1), ('Falscher Artikel geliefert', 20, 1), ('Artikel beschädigt angekommen', 30, 1), ('Artikel passt nicht / nicht kompatibel', 40, 1), ('Lieferung zu spät', 50, 1), ('Anderer Grund', 99, 1);