#!/usr/bin/env bash # # Setzt die Test-DB auf einen realistischen Holzleitner-Datenstand: # 8 Elektrogeräte-Lieferungen für Personalnummer 1001, Mix aus Standard- # und Filial-Items. # # Im Gegensatz zu `reset_test_tour.sh` (nur Item-Status zurücksetzen) # baut dieses Skript Stammdaten + Lieferungen komplett neu auf. Idempotent: # vorhandene Test-Touren der Accounts 1001/1002 werden gelöscht (CASCADE # räumt deliveries / items / scan_audit / notes mit), Customer- und # Article-Stamm wird ersetzt. # # Tour-Datum: # * ohne Argument → heute (CURRENT_DATE) # * mit Datum YYYY-MM-DD → genau dieser Tag # # Aufruf: # ./tool/seed_demo_data.sh # Tour für heute # ./tool/seed_demo_data.sh 2026-06-01 # Tour für ein bestimmtes Datum # TOUR_DATE=2026-06-01 ./tool/seed_demo_data.sh # alternativ via Env set -euo pipefail CONTAINER="${CONTAINER:-holzleitner-postgres}" DB_USER="${DB_USER:-holzleitner}" DB_NAME="${DB_NAME:-holzleitner}" # Datum aus erstem Argument oder TOUR_DATE-Env. Leer = heute. TOUR_DATE="${1:-${TOUR_DATE:-}}" if [ -n "$TOUR_DATE" ]; then if ! [[ "$TOUR_DATE" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then echo "✗ Ungültiges Datum '$TOUR_DATE'. Erwartet: YYYY-MM-DD." >&2 exit 1 fi # SQL-Literal — der Wert ist durch die Regex oben auf reine Ziffern/Bindestriche # beschränkt, daher kein Injection-Risiko. TOUR_DATE_EXPR="DATE '$TOUR_DATE'" DATE_LABEL="$TOUR_DATE" else TOUR_DATE_EXPR="CURRENT_DATE" DATE_LABEL="heute" fi if ! docker inspect "$CONTAINER" >/dev/null 2>&1; then echo "✗ Container '$CONTAINER' läuft nicht. Starte docker compose up -d." >&2 exit 1 fi echo "→ Seed Demo-Daten (8 Elektrogeräte-Lieferungen, PN 1001, Tour-Datum: $DATE_LABEL) …" docker exec -i "$CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -v ON_ERROR_STOP=1 -q \ -v tour_date_expr="$TOUR_DATE_EXPR" <<'SQL' BEGIN; -- ── 1. Alte Test-Daten räumen ──────────────────────────────────────── -- Tours mit CASCADE räumt deliveries → delivery_items → scan_audit ab. DELETE FROM tours WHERE account_id IN (1001, 1002); -- Existierende Test-Customer und Custom-Artikel wegwerfen — sie können -- jetzt sauber durch realistische Daten ersetzt werden. DELETE FROM customers WHERE erp_customer_id BETWEEN 4700 AND 5200; DELETE FROM articles WHERE article_number IN ( 'BRETT-200','PALETTE-EUR','FRACHT-PAUSCH','NEU-BALKEN', 'KS-EXP-200','WM-BOS-7K','TR-SIE-8K','SP-MIE-CL', 'BO-AEG-PY','MW-SAM-23','ST-GAG-IN','DH-MIE-AC' ); -- ── 2. Elektrogeräte-Stamm ─────────────────────────────────────────── -- Default-Warehouse setzen wir nur dort, wo das Backend-Schema das -- semantisch erwartet (Lager-Hint im ERP). Die *tatsächliche* Lager- -- Zuordnung pro Lieferposition kommt unten in delivery_items.warehouse_id. INSERT INTO articles (id, article_number, name, scannable, default_warehouse_id) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa001', 'KS-EXP-200', 'Kühl-Gefrierkombi Exquisit 200L', true, '11111111-1111-1111-1111-111111111111'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa002', 'WM-BOS-7K', 'Waschmaschine Bosch WAU28T70 7kg', true, '11111111-1111-1111-1111-111111111111'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa003', 'TR-SIE-8K', 'Wärmepumpentrockner Siemens iQ500 8kg', true, '11111111-1111-1111-1111-111111111111'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa004', 'SP-MIE-CL', 'Geschirrspüler Miele G5210 Classic', true, '11111111-1111-1111-1111-111111111111'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa005', 'BO-AEG-PY', 'Einbau-Backofen AEG Pyrolyse', true, '11111111-1111-1111-1111-111111111112'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa006', 'MW-SAM-23', 'Mikrowelle Samsung MS23K3513 23L', true, '11111111-1111-1111-1111-111111111111'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa007', 'ST-GAG-IN', 'Induktions-Standherd Gaggenau CI491', true, '11111111-1111-1111-1111-111111111112'), ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa008', 'DH-MIE-AC', 'Dunstabzugshaube Miele PUR98W', true, '11111111-1111-1111-1111-111111111111'); -- ── 3. Kunden (BGL-Region) ─────────────────────────────────────────── INSERT INTO customers (id, erp_customer_id, name, street, house_number, postal_code, city, country) VALUES ('cccccccc-cccc-cccc-cccc-ccccccccc001', 5101, 'Familie Bauer', 'Marktplatz', '5', '83435', 'Bad Reichenhall', 'Deutschland'), ('cccccccc-cccc-cccc-cccc-ccccccccc002', 5102, 'Familie Hofer', 'Ludwigstraße', '12', '83435', 'Bad Reichenhall', 'Deutschland'), ('cccccccc-cccc-cccc-cccc-ccccccccc003', 5103, 'Familie Steiner', 'Bahnhofstraße', '8', '83454', 'Anger', 'Deutschland'), ('cccccccc-cccc-cccc-cccc-ccccccccc004', 5104, 'Familie Mayr', 'Hauptstraße', '22', '83471', 'Berchtesgaden', 'Deutschland'), ('cccccccc-cccc-cccc-cccc-ccccccccc005', 5105, 'Familie Wagner', 'Wittelsbacherstraße', '3', '83435', 'Bad Reichenhall', 'Deutschland'), ('cccccccc-cccc-cccc-cccc-ccccccccc006', 5106, 'Familie Berger', 'Salzburger Straße', '45', '83454', 'Anger', 'Deutschland'), ('cccccccc-cccc-cccc-cccc-ccccccccc007', 5107, 'Familie Huber', 'Reichenhaller Straße', '10', '83483', 'Bischofswiesen', 'Deutschland'), ('cccccccc-cccc-cccc-cccc-ccccccccc008', 5108, 'Familie Lechner', 'Maximilianstraße', '15', '83435', 'Bad Reichenhall', 'Deutschland'); -- Ansprechpartner — eine Person pro Familie, primär als Telefon-Anker. INSERT INTO customer_contacts (id, customer_id, name, phone, email) VALUES ('dddddddd-dddd-dddd-dddd-ddddddddd001', 'cccccccc-cccc-cccc-cccc-ccccccccc001', 'Martin Bauer', '+49 8651 12345', NULL), ('dddddddd-dddd-dddd-dddd-ddddddddd002', 'cccccccc-cccc-cccc-cccc-ccccccccc002', 'Anna Hofer', '+49 8651 23456', 'a.hofer@example.de'), ('dddddddd-dddd-dddd-dddd-ddddddddd003', 'cccccccc-cccc-cccc-cccc-ccccccccc003', 'Josef Steiner', '+49 8656 34567', NULL), ('dddddddd-dddd-dddd-dddd-ddddddddd004', 'cccccccc-cccc-cccc-cccc-ccccccccc004', 'Sabine Mayr', '+49 8652 45678', NULL), ('dddddddd-dddd-dddd-dddd-ddddddddd005', 'cccccccc-cccc-cccc-cccc-ccccccccc005', 'Thomas Wagner', '+49 8651 56789', 't.wagner@example.de'), ('dddddddd-dddd-dddd-dddd-ddddddddd006', 'cccccccc-cccc-cccc-cccc-ccccccccc006', 'Petra Berger', '+49 8656 67890', NULL), ('dddddddd-dddd-dddd-dddd-ddddddddd007', 'cccccccc-cccc-cccc-cccc-ccccccccc007', 'Franz Huber', '+49 8652 78901', NULL), ('dddddddd-dddd-dddd-dddd-ddddddddd008', 'cccccccc-cccc-cccc-cccc-ccccccccc008', 'Maria Lechner', '+49 8651 89012', 'm.lechner@example.de'); -- ── 4. Tour für PN 1001 ─────────────────────────────────────────────── -- Datum kommt als psql-Variable (Default CURRENT_DATE, sonst DATE 'YYYY-MM-DD'). INSERT INTO tours (id, account_id, tour_date, synced_at) VALUES ('55555555-5555-5555-5555-555555555555', 1001, :tour_date_expr, NOW()); -- ── 5. Lieferungen ─────────────────────────────────────────────────── -- erp_belegart_id = 1 (Auftragsbestätigung, AB) wie in den ursprünglichen -- Seeds. sort_order entspricht der ERP-Vorgabe; die App kann nachträglich -- über PUT /tours/{id}/delivery-order anders sortieren. -- Payment-Method-IDs (siehe Migration 0008): -- cash = 99999999-9999-9999-9999-999999999901 -- ec_card = 99999999-9999-9999-9999-999999999902 -- invoice = 99999999-9999-9999-9999-999999999904 -- (credit_card wurde aus den Stammdaten entfernt — Migration 0021) INSERT INTO deliveries ( id, tour_id, erp_belegart_id, erp_belegnummer, customer_id, snap_street, snap_house_number, snap_postal_code, snap_city, snap_country, assigned_car_id, desired_time, special_agreements, state, state_reason, sort_order, prepaid_amount, payment_method_id ) VALUES -- Bauer: voll vorab bezahlt (Online-Kauf), Methode bleibt der ERP-Default (cash) ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee001', '55555555-5555-5555-5555-555555555555', 1, 'AB-2026-1001', 'cccccccc-cccc-cccc-cccc-ccccccccc001', 'Marktplatz', '5', '83435', 'Bad Reichenhall', 'Deutschland', NULL, '08:30 – 10:00', NULL, 'active', NULL, 1, 899.00, '99999999-9999-9999-9999-999999999901'), -- Hofer: nichts vorab, EC bei Lieferung (Wasch+Trockner) ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee002', '55555555-5555-5555-5555-555555555555', 1, 'AB-2026-1002', 'cccccccc-cccc-cccc-cccc-ccccccccc002', 'Ludwigstraße', '12', '83435', 'Bad Reichenhall', 'Deutschland', NULL, '09:00 – 11:00', 'Bitte alte Geräte mitnehmen', 'active', NULL, 2, 0.00, '99999999-9999-9999-9999-999999999902'), -- Steiner: 200 EUR Anzahlung, Rest auf Rechnung ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee003', '55555555-5555-5555-5555-555555555555', 1, 'AB-2026-1003', 'cccccccc-cccc-cccc-cccc-ccccccccc003', 'Bahnhofstraße', '8', '83454', 'Anger', 'Deutschland', NULL, NULL, NULL, 'active', NULL, 3, 200.00, '99999999-9999-9999-9999-999999999904'), -- Mayr: Großgerät, EC bei Lieferung ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee004', '55555555-5555-5555-5555-555555555555', 1, 'AB-2026-1004', 'cccccccc-cccc-cccc-cccc-ccccccccc004', 'Hauptstraße', '22', '83471', 'Berchtesgaden', 'Deutschland', NULL, '13:00 – 15:00', 'Einbau erfolgt durch Servicepartner', 'active', NULL, 4, 0.00, '99999999-9999-9999-9999-999999999902'), -- Wagner: nichts vorab, Bar ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee005', '55555555-5555-5555-5555-555555555555', 1, 'AB-2026-1005', 'cccccccc-cccc-cccc-cccc-ccccccccc005', 'Wittelsbacherstraße', '3', '83435', 'Bad Reichenhall', 'Deutschland', NULL, NULL, NULL, 'active', NULL, 5, 0.00, '99999999-9999-9999-9999-999999999901'), -- Berger: 500 EUR Anzahlung, Rest EC ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee006', '55555555-5555-5555-5555-555555555555', 1, 'AB-2026-1006', 'cccccccc-cccc-cccc-cccc-ccccccccc006', 'Salzburger Straße', '45', '83454', 'Anger', 'Deutschland', NULL, '11:00 – 13:00', NULL, 'active', NULL, 6, 500.00, '99999999-9999-9999-9999-999999999902'), -- Huber: nichts vorab, Rechnung (Stammkunde) ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee007', '55555555-5555-5555-5555-555555555555', 1, 'AB-2026-1007', 'cccccccc-cccc-cccc-cccc-ccccccccc007', 'Reichenhaller Straße', '10', '83483', 'Bischofswiesen', 'Deutschland', NULL, NULL, 'Anlieferung Tiefgaragen-Zugang', 'active', NULL, 7, 0.00, '99999999-9999-9999-9999-999999999904'), -- Lechner: nichts vorab, Bar ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee008', '55555555-5555-5555-5555-555555555555', 1, 'AB-2026-1008', 'cccccccc-cccc-cccc-cccc-ccccccccc008', 'Maximilianstraße', '15', '83435', 'Bad Reichenhall', 'Deutschland', NULL, '15:30 – 17:00', NULL, 'active', NULL, 8, 0.00, '99999999-9999-9999-9999-999999999901'); -- Ansprechpartner pro Lieferung (1:1). INSERT INTO delivery_contact_persons (delivery_id, customer_contact_id) VALUES ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee001', 'dddddddd-dddd-dddd-dddd-ddddddddd001'), ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee002', 'dddddddd-dddd-dddd-dddd-ddddddddd002'), ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee003', 'dddddddd-dddd-dddd-dddd-ddddddddd003'), ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee004', 'dddddddd-dddd-dddd-dddd-ddddddddd004'), ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee005', 'dddddddd-dddd-dddd-dddd-ddddddddd005'), ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee006', 'dddddddd-dddd-dddd-dddd-ddddddddd006'), ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee007', 'dddddddd-dddd-dddd-dddd-ddddddddd007'), ('eeeeeeee-eeee-eeee-eeee-eeeeeeeee008', 'dddddddd-dddd-dddd-dddd-ddddddddd008'); -- ── 6. Items pro Lieferung ─────────────────────────────────────────── -- 1 Stück pro Gerät (Elektrogeräte-Geschäft: pro Belegzeile genau ein -- Gerät). Filial-Items (Backofen, Standherd) landen explizit auf -- Filiale Freilassing, weil die Geräte zu sperrig für das Standardlager sind. INSERT INTO delivery_items ( id, delivery_id, article_id, required_quantity, warehouse_id, belegzeilen_nr, komponenten_artikel_nr, scanned_quantity, scan_status, held_reason ) VALUES -- Bauer: Kühl-Gefrierkombi ('ffffffff-ffff-ffff-ffff-fffffffff001', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee001', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa001', 1, '11111111-1111-1111-1111-111111111111', 1, NULL, 0, 'in_progress', NULL), -- Hofer: Waschmaschine + Trockner ('ffffffff-ffff-ffff-ffff-fffffffff002', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee002', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa002', 1, '11111111-1111-1111-1111-111111111111', 1, NULL, 0, 'in_progress', NULL), ('ffffffff-ffff-ffff-ffff-fffffffff003', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee002', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa003', 1, '11111111-1111-1111-1111-111111111111', 2, NULL, 0, 'in_progress', NULL), -- Steiner: Geschirrspüler ('ffffffff-ffff-ffff-ffff-fffffffff004', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee003', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa004', 1, '11111111-1111-1111-1111-111111111111', 1, NULL, 0, 'in_progress', NULL), -- Mayr: NUR Filiale (Backofen) — UX-Test „Standardlager fertig — Filiale offen" ('ffffffff-ffff-ffff-ffff-fffffffff005', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee004', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa005', 1, '11111111-1111-1111-1111-111111111112', 1, NULL, 0, 'in_progress', NULL), -- Wagner: Mikrowelle + Dunstabzugshaube ('ffffffff-ffff-ffff-ffff-fffffffff006', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee005', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa006', 1, '11111111-1111-1111-1111-111111111111', 1, NULL, 0, 'in_progress', NULL), ('ffffffff-ffff-ffff-ffff-fffffffff007', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee005', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa008', 1, '11111111-1111-1111-1111-111111111111', 2, NULL, 0, 'in_progress', NULL), -- Berger: drei Geräte (alle Standard) ('ffffffff-ffff-ffff-ffff-fffffffff008', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee006', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa001', 1, '11111111-1111-1111-1111-111111111111', 1, NULL, 0, 'in_progress', NULL), ('ffffffff-ffff-ffff-ffff-fffffffff009', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee006', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa002', 1, '11111111-1111-1111-1111-111111111111', 2, NULL, 0, 'in_progress', NULL), ('ffffffff-ffff-ffff-ffff-fffffffff010', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee006', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa006', 1, '11111111-1111-1111-1111-111111111111', 3, NULL, 0, 'in_progress', NULL), -- Huber: NUR Filiale (Standherd) — UX-Test „nur Filiale" ('ffffffff-ffff-ffff-ffff-fffffffff011', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee007', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa007', 1, '11111111-1111-1111-1111-111111111112', 1, NULL, 0, 'in_progress', NULL), -- Lechner: Spüler (Standard) + Backofen (Filiale) — UX-Test „gemischt" ('ffffffff-ffff-ffff-ffff-fffffffff012', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee008', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa004', 1, '11111111-1111-1111-1111-111111111111', 1, NULL, 0, 'in_progress', NULL), ('ffffffff-ffff-ffff-ffff-fffffffff013', 'eeeeeeee-eeee-eeee-eeee-eeeeeeeee008', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa005', 1, '11111111-1111-1111-1111-111111111112', 2, NULL, 0, 'in_progress', NULL); -- Stückpreise (brutto, EUR) pro Artikel. Der Warenwert einer Lieferung = -- Σ unit_price × ausgelieferte Menge (Soll − Gutschrift). Plausible Demo-Werte; -- das ERP-Sync-Makro liefert die Preise später live mit. UPDATE delivery_items di SET unit_price = CASE di.article_id WHEN 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa001' THEN 899.00 -- Kühl-Gefrierkombi WHEN 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa002' THEN 649.00 -- Waschmaschine WHEN 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa003' THEN 599.00 -- Trockner WHEN 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa004' THEN 549.00 -- Geschirrspüler WHEN 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa005' THEN 499.00 -- Backofen WHEN 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa006' THEN 199.00 -- Mikrowelle WHEN 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa007' THEN 749.00 -- Standherd WHEN 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaa008' THEN 329.00 -- Dunstabzugshaube ELSE unit_price END FROM deliveries d WHERE d.id = di.delivery_id AND d.tour_id = '55555555-5555-5555-5555-555555555555'; COMMIT; \echo \echo --- ARTIKEL --- SELECT article_number, name, scannable FROM articles ORDER BY article_number; \echo \echo --- KUNDEN --- SELECT erp_customer_id, name, postal_code, city FROM customers ORDER BY erp_customer_id; \echo \echo --- TOUR --- SELECT account_id, tour_date, synced_at FROM tours WHERE id = '55555555-5555-5555-5555-555555555555'; \echo \echo --- LIEFERUNGEN (PN 1001) --- SELECT d.sort_order, d.erp_belegnummer, c.name AS kunde, d.snap_city FROM deliveries d JOIN customers c ON c.id = d.customer_id WHERE d.tour_id = '55555555-5555-5555-5555-555555555555' ORDER BY d.sort_order; \echo \echo --- ITEMS PRO LIEFERUNG --- SELECT d.erp_belegnummer, di.belegzeilen_nr, a.article_number, a.name, w.name AS lager, di.required_quantity FROM delivery_items di JOIN deliveries d ON d.id = di.delivery_id JOIN articles a ON a.id = di.article_id JOIN warehouses w ON w.id = di.warehouse_id WHERE d.tour_id = '55555555-5555-5555-5555-555555555555' ORDER BY d.sort_order, di.belegzeilen_nr; SQL echo "✓ Demo-Daten geseedet (Tour-Datum: $DATE_LABEL)."