- output_location (Räumlichkeit): Neues Textfeld am Abgang für Raum/Ort des Verbrauchers. DB-Migration, Backend (AJAX), Frontend (Website + PWA), Anzeige im Schaltplan (kursiv) und in PDF-Tabellen. - Verteilungs-Tabellen: Kundenansicht (A4, Nr/Verbraucher/Räumlichkeit) und Technikeransicht (A4, R.Klem/FI/Nr/Verbraucher/Räumlichkeit/Typ) im Leitungslaufplan-PDF. Gruppiert nach Feld/Reihe mit automatischem Seitenumbruch. - Bundled-Terminals Checkbox: Im Website-Abgang-Dialog (war vorher nur PWA). - PWA: Diverse Verbesserungen, Service Worker v12.4, Connection-Modal erweitert. - Typ-Flags: has_product auch für Gebäudetypen, Equipment-Typ Erweiterungen. - CLAUDE.md + Doku aktualisiert. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
18 KiB
Executable file
CLAUDE_CODE_DISABLE_AUTO_MEMORY=0
KundenKarte Module - Entwicklungshinweise
Dolibarr App Navigation (Vor/Zurück Pfeile)
Problem
Die Dolibarr Mobile App hat eigene Navigations-Pfeile (vorheriger/nächster Kunde), die zwischen Datensätzen navigieren. Diese verwenden andere Parameter als unsere Module erwarten:
- Kunden-Navigation: Dolibarr verwendet
socid, Module erwarten oftid - Kontakt-Navigation: Dolibarr verwendet
contactid, Module erwarten oftid
Wenn man diese Pfeile auf einem Modul-Tab verwendet, verliert das Modul die ID und zeigt einen Fehler oder leere Seite.
Lösung: Beide Parameter akzeptieren
In JEDEM Tab-PHP-File muss am Anfang beide Parameter akzeptiert werden:
Für Kunden-Tabs (thirdparty):
// Get parameters
// Support both 'id' and 'socid' for compatibility with Dolibarr's customer navigation arrows
$id = GETPOSTINT('id');
if ($id <= 0) {
$id = GETPOSTINT('socid');
}
Für Kontakt-Tabs (contact):
// Get parameters
// Support both 'id' and 'contactid' for compatibility with Dolibarr's contact navigation arrows
$id = GETPOSTINT('id');
if ($id <= 0) {
$id = GETPOSTINT('contactid');
}
Betroffene Dateien in diesem Modul
tabs/anlagen.php- Kunden-Anlagen (socid)tabs/favoriteproducts.php- Kunden-Favoriten (socid)tabs/contact_anlagen.php- Kontakt-Anlagen (contactid)tabs/contact_favoriteproducts.php- Kontakt-Favoriten (contactid)
Best Practices für zukünftige Module
- IMMER beide Parameter akzeptieren -
idUNDsocid/contactid - Tab-Definition in modXxx.class.php verwendet
?id=__ID__- das ist korrekt - Dolibarr's
dol_banner_tab()generiert die Navigationspfeile mitsocid/contactid - Fallback bei fehlender ID - zur Liste weiterleiten, nicht Fehler zeigen:
if ($id <= 0) {
header('Location: '.DOL_URL_ROOT.'/societe/list.php');
exit;
}
Mobile Ansicht - Einheitliche Button-Größen
Problem
Auf mobilen Geräten haben die Buttons (Kompakt, Aufklappen, Einklappen, PDF Export) unterschiedliche Größen.
Lösung
CSS Media Queries für einheitliche Button-Größen:
@media (max-width: 768px) {
.kundenkarte-tree-controls {
justify-content: center !important;
flex-wrap: wrap !important;
gap: 8px !important;
}
.kundenkarte-tree-controls .button {
flex: 1 1 auto !important;
min-width: 80px !important;
max-width: 150px !important;
padding: 10px 8px !important;
font-size: 12px !important;
text-align: center !important;
}
}
@media (max-width: 480px) {
/* 2x2 Grid auf sehr kleinen Bildschirmen */
.kundenkarte-tree-controls {
display: grid !important;
grid-template-columns: 1fr 1fr !important;
}
}
Migrationen
Alle Datenbankänderungen werden als idempotente Migrationen in modKundenKarte.class.php implementiert:
runMigrations()wird bei jeder Modulaktivierung aufgerufen- Jede Migration prüft zuerst, ob die Änderung bereits existiert
- Später werden Migrationen entfernt und Tabellen direkt korrekt erstellt
Dateistruktur
Tabs
tabs/anlagen.php- Hauptansicht für Anlagen auf Kundenebenetabs/contact_anlagen.php- Anlagen für Kontaktetabs/favoriteproducts.php- Lieblingsprodukte auf Kundenebenetabs/contact_favoriteproducts.php- Lieblingsprodukte für Kontakte
Admin
admin/anlage_types.php- Verwaltung der Element-Typenadmin/building_types.php- Verwaltung der Gebäude-Typenadmin/equipment_types.php- Verwaltung der Equipment-Typenadmin/setup.php- Modul-Einstellungen
Klassen (class/)
anlage.class.php- Haupt-Anlage-Klasseanlagetype.class.php- Element-Typen (fetchAllBySystem mit color!)buildingtype.class.php- Gebäude-Typenanlageaccessory.class.php- Zubehör mit CRUD + Lieferantenbestellunganlageconnection.class.php- Kabelverbindungen (Anlagen-Ebene)anlagefile.class.php- Datei-Anhängeanlagebackup.class.php- Backup/Restoreauditlog.class.php- Änderungsprotokollequipment.class.php- Equipment-Instanzen auf Hutschienenequipmenttype.class.php- Equipment-Typ-Vorlagen (LS, FI, Neozed etc.)equipmentcarrier.class.php- Hutschienen (DIN-Rails)equipmentpanel.class.php- Schaltschrankfelder (Panels)equipmentconnection.class.php- Verbindungen im Schaltplan-Editorterminalbridge.class.php- Terminal-Brückenmediumtype.class.php- Leitungstypenbusbartype.class.php- Sammelschienen-Typen
Libraries (lib/)
kundenkarte.lib.php- Allgemeine Hilfs-Funktionengraph_view.lib.php- Shared Graph-Funktionen (Toolbar, Container, Legende)wiring_diagram.lib.php- Leitungslaufplan + Verteilungs-Tabellen (~2.130 Zeilen)
AJAX-Endpunkte (ajax/) — 30+ Dateien
anlage.php- Anlagen CRUDequipment.php- Equipment CRUD + Produkt-Sucheequipment_carrier.php- Hutschienen CRUDequipment_panel.php- Panel CRUDequipment_connection.php- Verbindungen CRUDanlage_accessory.php- Zubehör CRUD + Bestellunggraph_data.php- Cytoscape Graph-Datengraph_save_positions.php- Graph-Positionen speichernexport_schematic_pdf.php- Schaltplan PDF-Exportexport_wiring_diagram_pdf.php- Leitungslaufplan PDF-Export (separates Feature)export_tree_pdf.php- Baum PDF-Exportfile_preview.php- Datei-Vorschau Tooltippwa_api.php- PWA-Endpoints
Frontend
js/kundenkarte.js- Haupt-JS (~15.600 Zeilen)js/kundenkarte_cytoscape.js- Graph-JS (~900 Zeilen)js/pwa.js- PWA-JS (~3.400 Zeilen)css/kundenkarte.css- Alle Styles (Dark Mode Theme)css/pwa.css- PWA-Styles
Wichtige Hinweise
FontAwesome Icons
- Dolibarr verwendet FontAwesome 4.x Format:
fa fa-icon-name - NICHT:
fas fa-icon-nameoderfar fa-icon-name
Badge-Farben
- Können pro Feld in Admin > Element-Typen konfiguriert werden
- Spalte
badge_colorinllx_kundenkarte_anlage_type_field - Hex-Format:
#RRGGBB
Datei-Vorschau Tooltip
- AJAX-Endpoint:
ajax/file_preview.php - Zeigt Thumbnails für Bilder, Icons für Dokumente
- Hover über Datei-Badge im Baum
PWA Mobile App
Übersicht
Offline-fähige Progressive Web App für Elektriker zur Schaltschrank-Dokumentation vor Ort.
Dateien
pwa.php- Haupteinstieg (HTML/CSS/JS Container, lädt jQuery aus Dolibarr)pwa_auth.php- Token-basierte Authentifizierung (15 Tage gültig)ajax/pwa_api.php- Alle AJAX-Endpoints für die PWAjs/pwa.js- Komplette App-Logik (jQuery, als IIFE mit jQuery-Parameter)css/pwa.css- Mobile-First Design, Dolibarr Dark Theme Variablensw.js- Service Worker für Offline-Cache (v12.4)manifest.json- Web App Manifest für Installation
Workflow
- Login mit Dolibarr-Credentials → Token wird lokal gespeichert
- Kunde suchen → Anlagen werden gecached
- Kontakt-Adressen (Gebäude/Standorte) aufklappen → Anlagen pro Adresse
- Anlage mit Schaltplan-Editor auswählen → Daten werden gecached
- Offline arbeiten: Hutschienen, Automaten hinzufügen
- Änderungen werden in lokaler Queue gespeichert
- Bei Internetverbindung: Automatische Synchronisierung
Design-System
- CSS-Variablen basierend auf Dolibarr Dark Theme (
--colorbackbody,--colortext, etc.) - Theme-Farbe
--primarywird dynamisch aus Dolibarr-Config geladen (THEME_ELDY_TOPMENU_BACK1) - Buttons:
--butactionbg(goldbraun) statt blau - Header: sticky, primary-Farbe
Kontakt-Adressen
get_anlagenAPI liefertanlagen(Kunden-Ebene) +contacts(Adressen)- Kontakt-Gruppen (Gebäude/Standorte) werden OBEN als vertikale Liste dargestellt
- Chevron-Pfeil zeigt Aufklapp-Status, Anlagen werden bei Klick geladen
- Kunden-Anlagen darunter mit Kunden-Adresse als Trennlabel
get_contact_anlagenAPI lädt Anlagen pro Kontakt-Adresse bei Bedarf- Layout: Alles untereinander (Handy-optimiert), keine Grid-Spalten
Schaltplan-Editor
- Equipment-Blöcke als CSS Grid (
grid-template-columns: repeat(totalTE, 1fr)) - Blöcke positioniert per
grid-columnbasierend aufposition_teundwidth_te - Equipment-Blöcke: 80px Höhe, Sicherungsautomat-Optik mit Border und Schatten
block_labelundblock_coloraus Backend (wie Website)- Abgang-Labels (Outputs) werden über/unter den Automaten angezeigt
- Connections mit
fk_target IS NULL= Ausgänge/Abgänge - Intelligente Positionsberechnung mit Lücken-Erkennung (getMaxGap)
- +-Button disabled wenn Hutschiene voll, Typ-Buttons gefiltert nach verfügbarer Breite
- Hutschiene zeigt belegt/gesamt TE
Navigation & State
- Browser-History Support (hardware Zurück-Button funktioniert)
- Session-State wird in
sessionStoragegespeichert (Screen, Kunde, Anlage) - Bei Seiten-Refresh wird letzter Zustand wiederhergestellt
- Popstate-Handler: Lädt Anlagen-Daten nach falls Liste leer (z.B. nach Refresh→Back)
- Sync-Button lädt jetzt erst Offline-Queue, dann Daten neu
Anlagen-Übersicht
- Anlagen-Cards: Horizontales Layout (Icon links, Titel rechts), volle Breite
- Einspaltiges vertikales Layout - optimiert fürs Handy
Token-Authentifizierung
- Tokens enthalten: user_id, login, created, expires, hash
- Hash = MD5(user_id + login + MAIN_SECURITY_SALT)
- Gültigkeit: 15 Tage
- Gespeichert in localStorage
$user->getrights()wird nach Token-Validierung aufgerufen
Offline-Sync
- Alle Änderungen werden in
offlineQueue(localStorage) gespeichert - Badge zeigt Anzahl ungesyncte Änderungen
- Sync-Button oder automatisch bei Online-Event
- Bei Sync werden Aktionen der Reihe nach ausgeführt
Installation auf Smartphone
- PWA im Browser öffnen:
https://domain/dolibarr/custom/kundenkarte/pwa.php - Browser-Menü → "Zum Startbildschirm hinzufügen"
- App öffnet sich als Standalone ohne Browser-UI
FI/RCD-Schutzgruppen (v7.5)
- Equipment kann einem Schutzgerät (FI/RCD) zugeordnet werden
fk_protectioninllx_kundenkarte_equipmentspeichert die ID des schützenden Equipment- Im Editor: Farbige Ränder zeigen Schutzgruppen-Zugehörigkeit
get_protection_devicesAPI liefert verfügbare Schutzgeräte für Dropdown
Gebündelte Terminals (v7.5)
- Multi-Phasen-Abgänge für Drehstrom-Verbraucher (E-Herd, DLE)
bundled_terminals = 'all'in Connection bedeutet: Alle Terminals belegt- Im Editor: Ein Pfeil spannt über alle Terminals des Equipment
- Label wird zentriert über alle Terminals angezeigt
- Checkbox "Alle Terminals bündeln" im Abgang-Dialog (Website + PWA), nur bei Equipment mit >1 Terminal
Terminal-Konfiguration (v7.5)
terminals_configJSON im Equipment-Typ definiert Terminal-Positionen- Format:
{"terminals":[{"pos":"top"},{"pos":"top"},{"pos":"bottom"}...]} getTerminalCount(type, position, fallback)zählt Terminals pro Position- Ermöglicht: 4 TE Breite aber nur 3 Terminals (z.B. Neozed 3F)
Grid-Layout (5 Zeilen)
- Zeile 1: Abgang-Labels oben (terminal-label-cell.label-row-top)
- Zeile 2: Terminal-Punkte oben (terminal-point.terminal-row-top)
- Zeile 3: Equipment-Blöcke
- Zeile 4: Terminal-Punkte unten (terminal-point.terminal-row-bottom)
- Zeile 5: Abgang-Labels unten (terminal-label-cell.label-row-bottom)
Ausgebaut-Status (v8.0)
Spalten
decommissioned(tinyint DEFAULT 0) inllx_kundenkarte_anlagedate_decommissioned(date NULL) inllx_kundenkarte_anlage
Verhalten
- Toggle per Button am Element im Baum und Graph
- Ausgebaute Elemente:
opacity: 0.4, dashed border, Badge "Ausgebaut" - Toggle-Button in Toolbar: Klasse
.show-decommissionedauf.kundenkarte-tree - Admin-Setting
KUNDENKARTE_SHOW_DECOMMISSIONEDfür Standard-Sichtbarkeit - Graph-View: Nodes mit Klasse
.decommissioned(35% opacity, dashed border)
Mein Betrieb / Werkzeuge (v8.5)
Übersicht
Eigene Seite für Firmen-Equipment (Werkzeuge, Maschinen, Messgeräte).
Dateien
werkzeuge.php- Baumansicht für eigene Firma (fk_soc = mysoc->id)class/anlageaccessory.class.php- Zubehör-Klasse mit CRUD + Bestellfunktionajax/anlage_accessory.php- AJAX-Endpunkte für Zubehör
System
- Neues System
WERKZEUG(ID 26) inllx_c_kundenkarte_anlage_system - Menüpunkt unter KundenKarte > Mein Betrieb
- System-Filter fix auf "WERKZEUG"
Produkt-Zuordnung
fk_productinllx_kundenkarte_anlageverknüpft mit Dolibarr-Produkt- Autocomplete-Suche via
ajax/equipment.php?action=get_products - Anzeige: Ref + Label + Preis unter Element im Baum
- Typ-Flag
has_product: Steuert ob Produkt-Zeile im Formular sichtbar ist data-has-productAttribut auf<option>für JS-Steuerung
Zubehör-System
- Tabelle
llx_kundenkarte_anlage_accessory(fk_anlage, fk_product, qty, rang, note) - Typ-Flag
has_accessoriessteuert Verfügbarkeit - Lieferantenbestellung via
CommandeFournisseurgenerierbar
Terminal-Farbpropagierung (v8.6)
Übersicht
Phasenfarben werden von den Eingängen (Anschlusspunkten) durch den gesamten Schaltplan propagiert.
Dual-Map System in JS
_terminalPhaseMap—{eqId: {termId: "L1"}}— Phasennamen für Busbar-Logik_terminalColorMap—{eqId: {termId: "#hex"}}— Tatsächliche Hex-Farben (vonconn.color)- Aufgebaut in
buildTerminalPhaseMap()(JS Zeile ~5499)
Propagierungsreihenfolge
- Inputs (Anschlusspunkte):
conn.colorals Startfarbe,connection_typeals Phase - Block-Durchreichung: Top-Terminal ↔ Bottom-Terminal (paarweise)
- Leitungen: Source → Target und umgekehrt
- Busbars: Nur eingespeiste Phasen verteilen (fedPhases/fedColors)
Farbzugriff
getTerminalConnectionColor(eqId, termId)— Liest_terminalColorMap, Fallback auf Connection-Farben- Input-Labels werden als farbige Badges angezeigt (Phase-Name als weißer Text auf inputColor-Hintergrund)
Phasenfarben (PHASE_COLORS)
L1: '#8B4513' (braun) L2: '#1a1a1a' (schwarz) L3: '#666666' (grau)
N: '#0066cc' (blau) PE: '#27ae60' (grün)
Leitungslaufplan PDF-Export (v8.6)
Übersicht
Normgerechter Stromlaufplan in aufgelöster Darstellung (DIN EN 61082) als PDF-Export. Komplett separates Feature — kann durch Löschen von 2 Dateien + 8 Zeilen rückstandsfrei entfernt werden.
Dateien
lib/wiring_diagram.lib.php— Kernlogik (~2.130 Zeilen)WiringDiagramAnalyzer— Lädt Daten, baut Phase-Map (PHP-Port), tracet StrompfadeWiringDiagramRenderer— Zeichnet PDF mit TCPDF
ajax/export_wiring_diagram_pdf.php— Endpoint- Buttons in
tabs/anlagen.php+tabs/contact_anlagen.php(je 4 Zeilen)
PDF-Inhalt (5 Teile)
- Leitungslaufplan (A3 quer) — L1/L2/L3 horizontal oben, vertikale Strompfade pro Abgang, FI/RCD + LS-Symbole, Abgang-Pfeile, N/PE unten
- Abgangsverzeichnis (A3 quer) — Tabelle pro Hutschiene mit: Abg.Nr, Bezeichnung, Phase, Absicherung, Kabel, Schutzgerät
- Kundenansicht (A4 hoch) —
renderKundenansicht()— Einfache Tabelle: Nr | Verbraucher | Räumlichkeit, gruppiert nach Feld/Reihe - Technikeransicht (A4 hoch) —
renderTechnikeransicht()— Erweiterte Tabelle: R.Klem | FI | Nr | Verbraucher | Räumlichkeit | Typ - Mini-Legende — Phasenfarben DIN VDE auf Seite 1 unten links
Abgangsnummer-Format
R{Reihe}.{Position} z.B. R1.3 = Carrier-Position 1, Equipment-TE-Position 3
Strompfad-Tracing
Pro Abgang (Connection mit fk_target = NULL):
- Source-Equipment = LS-Schalter
- Phase aus
terminalPhaseMap - FI/RCD über
Equipment.fk_protection - Kabel:
medium_type+medium_spec+medium_length - Sortierung: FI-Gruppe → Carrier-Position → Equipment-Position
Phase-Map (PHP-Port)
WiringDiagramAnalyzer::buildPhaseMap() ist ein 1:1 PHP-Port von JS buildTerminalPhaseMap():
- Iterativ (max 20 Durchläufe) bis keine Änderungen mehr
- Inputs → Block-Durchreichung → Leitungen → Busbar-Verteilung
VDE-Symbole
- LS-Schalter: Schräge Kontaktlinie + Auslöser-Rechteck
- FI/RCD: Rechteck mit Kreis + Vertikallinie (Differenzstrom-Symbol)
- Gezeichnet mit TCPDF-Primitiven (Line, Rect, Circle, Polygon)
Räumlichkeit / output_location (v8.6)
Übersicht
Zusätzliches Textfeld am Abgang (Output-Connection) für den Raum/Ort des Verbrauchers (z.B. "Küche", "Bad OG").
Datenbank
- Spalte
output_location(varchar 255) inllx_kundenkarte_equipment_connection - Migration:
migrate_v1110_output_location()inmodKundenKarte.class.php
Backend
EquipmentConnection::$output_location— Property, in create/update/fetchajax/equipment_connection.php— create_output + update + list_allajax/pwa_api.php— get_carrier_equipment + create_connection + update_connection
Frontend
- Website: Eingabefeld im
renderAbgangDialog()(kundenkarte.js) - PWA: Eingabefeld
#conn-locationim Connection-Modal (pwa.php + pwa.js) - Anzeige im Schaltplan:
- Website SVG:
<tspan>kursiv nach Label mit·Trennzeichen - PWA Grid:
<span class="output-location">kursiv unter dem Label-Text
- Website SVG:
- PDF: In Kundenansicht + Technikeransicht als eigene Tabellenspalte
Select2 mit Kategorie-Filter
Problem & Lösung
In anlagen.php und contact_anlagen.php gibt es einen Kategorie-Filter (Gebäude/Element), der die Typ-Options per JS filtert und Select2 neu initialisiert.
Wichtig: Nach initSelect2() muss der Wert mit .trigger("change") gesetzt werden,
damit Select2 den aktuellen Wert korrekt anzeigt:
initSelect2();
if (currentVal && $typeSelect.find('option[value="' + currentVal + '"]').length) {
$typeSelect.val(currentVal).trigger("change");
}
Ablauf in filterTypes()
currentValsichern- HTML aus
allOptionsHtmlzurücksetzen - Nicht passende Options entfernen
- Select2 initialisieren
- Wert mit
.trigger("change")wiederherstellen