dolibarr.idsconnect/CHANGELOG.md
data 81646f5ea4 feat(launch): Konfigurationsvalidierung & GlobalNotify-Integration v3.4
- Neue Funktion idsconnect_notify() für GlobalNotify-Benachrichtigungen
  mit Fallback auf dol_syslog falls Modul nicht installiert
- Neue Funktion idsconnect_validateSupplierConfig() prüft Supplier-
  Konfiguration vor dem Launch auf Vollständigkeit
- launch.php: Validierung vor Formular-Submit
  - Fehler (leeres Passwort): blockiert Launch, Redirect zur Konfiguration
  - Warnung (leerer Username): erlaubt Launch aber warnt User + Admin
- Löst Problem: Klux "Weiter"-Button fehlte weil ids_username leer war,
  Login schlug still fehl ohne jede Fehlermeldung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 12:58:23 +01:00

16 KiB
Executable file
Raw Permalink Blame History

IDS Connect Modul - Changelog

Projektinfo

  • Modul: IDS Connect für Dolibarr ERP
  • Modul-ID: 500025
  • Zweck: Punchout-Schnittstelle zu Elektrogroßhändlern (Sonepar, Kluxen)
  • Protokoll: IDS Connect 2.0/2.5 (Browser-basiertes Punchout)
  • Entwickler: Eduard Wisch / Claude AI

v3.4 - Klux-Support & Konfigurationsvalidierung (17.03.2026)

🐛 BUGFIX: Klux "Weiter"-Button fehlte

  • Problem: Beim WKS (Warenkorb senden) an Klux fehlte im Klux-Shop der "Weiter"-Button zur Bestellbestätigung.
  • Ursache: ids_username (→ name_kunde) war leer in der Klux-Supplier-Konfiguration. Ohne gültigen Login-Namen zeigt der Klux-Shop den Katalog, aber keinen IDS-Checkout-Button.
  • Fix: ids_username = ids-1222925 (Kundennummer) in der Produktiv-DB gesetzt.
  • Hintergrund: Bei deutschen Elektrogroßhändlern (Klux, Sonepar) wird die Kundennummer oft auch als Login-Username verwendet. Das name_kunde-Feld darf nicht leer sein.

Feature: Konfigurationsvalidierung vor IDS-Launch

Neue Validierung in launch.php bevor das Formular an den Großhändler-Shop gesendet wird:

  • Fehler (blockiert Launch): Kein Passwort konfiguriert → Redirect zur Supplier-Konfiguration
  • Warnung (erlaubt aber warnt): Kein Benutzername konfiguriert → name_kunde wäre leer → "Weiter"-Button fehlt im Shop
  • Verhindert das stille Fehlschlagen ("Shop lädt, aber kein Bestell-Button, niemand weiß warum")

Feature: GlobalNotify-Integration

  • Neue Funktion idsconnect_notify() in lib/idsconnect.lib.php
    • Sendet Benachrichtigungen an Admins über GlobalNotify (falls Modul aktiv)
    • Fallback auf dol_syslog() wenn GlobalNotify nicht installiert
    • Typen: error, warning, info, action
  • Neue Funktion idsconnect_validateSupplierConfig() in lib/idsconnect.lib.php
    • Prüft Supplier-Konfiguration vor dem Launch auf Vollständigkeit
    • Gibt strukturierte errors und warnings zurück
  • Bei unvollständiger Konfiguration: Admin erhält GlobalNotify-Meldung mit direktem Link zur Supplier-Konfigurationsseite

🔧 Technische Details

  • Validierte Felder: ids_password (Error), ids_username (Warning)
  • GlobalNotify-Typ: action für Fehler (Link zur Konfiguration), warning für Warnungen
  • Keine Code-Änderungen an der Formular-Generierung (idsconnect.class.php) - nur Vorbedingung in launch.php

v2.9 - Preis-Vergleich & Kritische Bugfixes (12.03.2026)

🐛 KRITISCHER BUGFIX: SQL-Spaltenname korrigiert

  • Problem: matchProducts() hat SQL-Fehler produziert wegen falscher Spalte pfp.qty (existiert nicht!)
  • Fix: Alle pfp.qtypfp.quantity ersetzt in:
  • Auswirkung: Vorher wurden ALLE Artikel als Freitext importiert (kein Produkt-Matching!)
  • Test: Artikel 0486597 wird jetzt korrekt als COK-WAG-2273-202-2F erkannt

🐛 BUGFIX: Produkt-Matching erweitert

  • Fix: p.status = 1p.tosell = 1 in matchProducts() und tab_supplierorder.php
  • Grund: Dolibarr verwendet tosell für verkaufbare Produkte, nicht status

Preis-Vergleich in Warenkorb-Import (cart_review.php)

  • Basis-Price-Vergleich: Shop-Preis (z.B. 12,88€/100 Stk) vs. DB-Preis (12,88€/100 Stk)
  • Vorteil: Keine Rundungsfehler mehr durch Stückpreis-Umrechnung
  • Berechnung:
    • shop_basis_price = raw_netprice (vom Shop empfangen)
    • db_basis_price = debug_price (aus DB geladen)
    • Deviation = ((shop - db) / db) × 100
  • DEBUG-Ausgabe für Admins: Zeigt Shop-Preis, DB-Preis, Einzelpreis zur Kontrolle
  • Farbcodierung:
    • Grün: ≤2% Abweichung
    • Gelb: 2-10% Abweichung
    • Rot: >10% Abweichung

Preis-Vergleich in Lieferantenbestellungen (tab_supplierorder.php)

  • Admin-Option: IDSCONNECT_PRICE_UPDATE_ENABLED (Standard: AUS)
  • Schwellwert: IDSCONNECT_PRICE_UPDATE_THRESHOLD (Standard: 5%)
  • Anzeige: Tabelle mit allen Positionen, die vom Schwellwert abweichen
  • Freitext-Warnung: Zeigt an, wenn Artikel nicht mit Dolibarr-Produkten verknüpft sind
  • Keine Auto-Updates: Nur Anzeige, keine automatische Preis-Aktualisierung

🔧 Technische Details

  • matchProducts(): Lädt jetzt pfp.quantity, pfp.price korrekt
  • Stückpreis-Berechnung: unit_price = price / quantity (mit Fallback qty=1)
  • Debug-Felder: debug_price und debug_qty für Basis-Price-Vergleich
  • Sprachdateien: Neue Keys für Preis-Verwaltung (de_DE)

v2.2 - Menü-Integration, ADL-Hooks & Admin-Erweiterung (19.02.2026)

Menü unter Einkauf/Lieferantenbestellungen

  • Kein eigenes Top-Menü mehr: IDS Connect ist jetzt unter Einkauf > Lieferantenbestellungen > IDS Connect eingegliedert
  • Untermenüs (Großhändler, Transaktionslog) als Level 2/3 unter dem IDS Connect Eintrag
  • Bessere Integration in den normalen Dolibarr-Workflow

ADL-Buttons auf Produkt-Lieferantenpreisen (Hook)

  • Neue Datei: class/actions_idsconnect.class.php - Hook-Klasse für pricesuppliercard
  • Zeigt ADL-Button (externer Link) direkt in der Lieferantenpreis-Tabelle auf Produktkarten
  • Button nur sichtbar wenn Lieferant mit IDS Connect Großhändler verknüpft UND Lieferanten-Artikelnummer vorhanden
  • Spalte erscheint nur wenn mindestens ein aktiver IDS-Supplier existiert
  • Gecachte DB-Abfragen für Performance (static-Cache pro Request)

Admin Setup-Seite erweitert

  • Großhändler-Schnellübersicht: Tabelle mit allen konfigurierten Großhändlern direkt auf der Einstellungsseite
  • Zeigt Name, URL, IDS-Version, Status (Aktiv/Inaktiv, Testmodus) pro Großhändler
  • Version prüfen: Button pro Großhändler für SV-Action (Schnittstellenversion)

Dashboard

  • Shop öffnen: Neuer LI-Button (Login-Info) neben dem WKE-Button auf der Übersichtsseite

Sprachdateien

  • IdsconnectShowInShop - Tooltip für ADL-Button in Preistabelle
  • IdsconnectCheckVersion - Button für Schnittstellenversion prüfen

v2.1 - WKS-Flow & URL-Handling (18.02.2026)

WKS (Warenkorb senden) - Live getestet mit Sonepar

  • WKS End-to-End: Lieferantenbestellung in Dolibarr anlegen → IDS Connect Tab → "Warenkorb senden" → Artikel im Sonepar-Shop vorausgefüllt → "Nur bestellen"
  • buildCartXml(): Von altem <Artikel>-Format auf IDS Connect 2.0 umgestellt
    • Namespace xmlns="http://www.itek.de/Shop-Anbindung/Warenkorb/"
    • <OrderItem> statt <Artikel>, <ArtNo>, <Kurztext>, <NetPrice>
    • PriceBasis=1 (Dolibarr-Preise sind bereits Stückpreise)
    • VAT aus MwSt-Satz der Bestellposition
  • launch.php: MwSt-Satz (tva_tx) und Einheit PCE in Warenkorb-Positionen
  • Bestellstatus: Setzt Lieferantenbestellung auf "Bestellt" nach WKS-Versand

URL-Handling (Cross-Domain-Fix)

  • Problem: $dolibarr_main_url_root war 192.168.155.1:8090 (intern, ohne Protokoll), User greift über awl.data-it-solution.de zu → Callback-Links waren kaputt
  • user_base_url-Tracking: Speichert beim Launch die Domain des Users (HTTP_HOST) in den Log-Request-Daten, callback.php liest diese für Links zurück
  • Protokoll-Prefix: Automatische http://-Ergänzung wenn :// fehlt
  • URL-Priorität für Callback-Links:
    1. user_base_url aus Log (Domain des Users beim Launch)
    2. IDSCONNECT_PUBLIC_URL aus Einstellungen
    3. $dolibarr_main_url_root als Fallback

Sonepar-Shop Buttons (Erkenntnisse)

  • "Warenkorb übergeben" = WKE-Callback zurück an Dolibarr (für Shop-Einkauf)
  • "Nur bestellen" = Bestellung direkt bei Sonepar auslösen (für WKS-Flow)
  • "Bestellen" = beides (übergeben + bestellen)
  • Bei WKS "Nur bestellen" verwenden, da Bestellung in Dolibarr bereits existiert

v2.0 - Sonepar Live-Integration (18.02.2026)

Kernproblem

Die erste Version konnte den Warenkorb von Sonepar nicht empfangen. Mehrere Probleme:

  1. enctype="multipart/form-data" fehlte im Launch-Formular
  2. XML-Parser erkannte das IDS Connect Format nicht
  3. Redirect nach Callback führte zum Login (Session-Problem)
  4. Preiseinheit (PriceBasis) wurde nicht berücksichtigt

Sonepar XML-Format (Erkenntnisse)

Sonepar sendet IDS XML im POST-Feld warenkorb mit folgender Struktur:

<Warenkorb xmlns="http://www.itek.de/Shop-Anbindung/Warenkorb/">
  <WarenkorbInfo>
    <Date>2026-02-18+01:00</Date>
    <Time>05:47:07+01:00</Time>
    <RueckgabeKZ>Warenkorbrückgabe</RueckgabeKZ>
    <Version>2.0</Version>
  </WarenkorbInfo>
  <Order>
    <OrderInfo>
      <ModeOfShipment>Lieferung</ModeOfShipment>
      <Cur>EUR</Cur>
    </OrderInfo>
    <DeliveryPlaceInfo>
      <Address>
        <Name1>...</Name1><Name2>...</Name2>
        <Street>...</Street><PCode>...</PCode>
        <City>...</City><Country>DE</Country>
      </Address>
    </DeliveryPlaceInfo>
    <OrderItem>
      <ArtNo>0351817</ArtNo>
      <Qty>100</Qty>
      <QU>PCE</QU>
      <Kurztext>Klauke Stossverbinder f.Massivleiter SV1525</Kurztext>
      <OfferPrice>26.8</OfferPrice>
      <NetPrice>16.88</NetPrice>
      <PriceBasis>100</PriceBasis>    <!-- Preis gilt für 100 Stück! -->
      <VAT>19</VAT>
      <TechnClarification>No</TechnClarification>
    </OrderItem>
  </Order>
</Warenkorb>

Wichtig: Namespace xmlns="http://www.itek.de/Shop-Anbindung/Warenkorb/" verhindert direkten SimpleXML-Zugriff → Namespace-Stripping nötig.

Änderungen

callback.php - Komplett-Rewrite auf v2.0

  • Versionskennung: IDSCONNECT_CALLBACK_VERSION = '2.0' zur Identifikation
  • Kein Redirect mehr: Zeigt Ergebnis direkt als HTML-Seite (NOLOGIN)
    • Vorher: header('Location: idsconnectindex.php?error=...') → Login-Problem
    • Nachher: idsconnectCallbackPage() rendert eigenständige HTML-Seite
  • 7 Datenquellen: Durchsucht POST[warenkorb], POST[cart], FILES[warenkorb], FILES[cart], erste hochgeladene Datei, alle POST-Felder nach XML, php://input
  • OCI-Format: Erkennt NEW_ITEM-* POST-Felder (SAP OCI Punchout)
  • Debug-Daten: Speichert immer alle empfangenen Daten in DB (response_data JSON)
  • Roh-XML: Speichert XML sofort in DB, auch bei Parse-Fehler
  • Interne Links: Verwendet $dolibarr_main_url_root statt DOL_URL_ROOT für korrekte Navigation nach Callback auf öffentlicher Domain

class/idsconnect.class.php - Parser erweitert

  • Format 5: IDS Connect 2.5 Warenkorb/Order/OrderItem hinzugefügt
  • Format 6: Namespace-Stripping - entfernt xmlns und Prefixe, versucht alle Format-Checks erneut auf bereinigtem XML
  • PriceBasis: Neues Feld PriceBasis/PE/Preiseinheit wird geparst
    • Einzelpreis = NetPrice / PriceBasis (z.B. 16,88 / 100 = 0,1688€/Stk)
    • Angebotspreis wird analog umgerechnet
    • preiseinheit und raw_netprice werden im Item-Array mitgegeben
  • VAT/MwSt: MwSt-Satz wird aus VAT/MwSt geparst und als mwst_satz gespeichert
  • Erweiterte Feldnamen: ArtNo, Kurztext, Langtext, NetPrice, OfferPrice, ManufacturerID, Hinweis in den Mapping-Arrays ergänzt
  • Debug-Logging: Root-Element und Kinder werden via dol_syslog geloggt
  • Bessere Fehlermeldung: Zeigt Root-Element und Kinder bei "Keine Artikel gefunden"

launch.php - Formular-Fix

  • enctype: enctype="multipart/form-data" zum Launch-Formular hinzugefügt (fehlte, dadurch kamen keine Callback-Daten an)

cart_review.php - Preisanzeige verbessert

  • PE-Info: Zeigt unter dem Stückpreis die Preiseinheit-Info: "16,88 / 100 Stk" wenn PriceBasis > 1
  • MwSt: Verwendet mwst_satz aus XML bei Bestellerstellung (statt 0%)

mockserver.php - Realitätsnäher

  • IDS Connect 2.5 Format: Generiert Warenkorb/Order/OrderItem statt altes <Artikel> Format
  • Namespace: Verwendet xmlns="http://www.itek.de/Shop-Anbindung/Warenkorb/" wie Sonepar
  • Neue Felder: PriceBasis, VAT im generierten XML

admin/setup.php - Erweiterte Konfiguration

  • Öffentliche URL: Feld für IDSCONNECT_PUBLIC_URL (Reverse-Proxy)
  • Callback-URL: Berechnete Anzeige (read-only, klickbar zum Kopieren)
  • Mock-Server URL: Berechnete Anzeige (immer intern)
  • WKS-Warnschwellen: Mengen- und Wertgrenzen konfigurierbar
  • WKS-PIN: Verschlüsselte PIN für Warenkorb-Senden

v1.0 - Initiale Entwicklung (17.02.2026)

Grundgerüst

  • Modul-Struktur nach Dolibarr-Standard (modIdsconnect.class.php)
  • Berechtigungssystem: read, use, config, delete
  • Mehrsprachig: de_DE, en_US
  • SQL-Tabellen: idsconnect_supplier, idsconnect_log

Dateien erstellt

Datei Zweck
class/idsconnect.class.php Kern-Klasse: Formular-Builder, XML-Parser, XML-Generator
class/idssupplier.class.php Großhändler-Konfiguration (URL, Login, Passwort)
class/idslog.class.php Transaktionslog (CRUD, Status-Updates)
callback.php HOOKURL-Empfänger, NOLOGIN-Seite
launch.php Formular-Generator für Shop-Weiterleitung
mockserver.php Test-Shop für lokale Entwicklung (NOLOGIN, nur Testmodus)
idsconnectindex.php Hauptseite mit Großhändler-Liste und Log
cart_review.php Empfangenen Warenkorb prüfen, Bestellung erstellen
supplier_card.php Großhändler-Konfigurationsseite
supplier_list.php Großhändler-Liste
log_list.php Log-Übersicht mit Filter
log_detail.php Log-Detailansicht (XML, Response, Fehler)
tab_supplierorder.php Tab auf Lieferantenbestellungen
test_connection.php AJAX-Verbindungstest
admin/setup.php Modul-Einstellungen
admin/about.php Über-Seite
lib/idsconnect.lib.php Hilfsfunktionen, Tab-Builder
build/buildzip.php Modul-ZIP erstellen

IDS Connect Actions

Kürzel Bedeutung Richtung Status
WKE Warenkorb empfangen IN Funktioniert (Sonepar getestet)
WKS Warenkorb senden OUT Funktioniert (Sonepar getestet)
ADL Artikel Deep-Link OUT Implementiert
LI Login-Info OUT Implementiert
SV Schnittstellenversion OUT Implementiert

Sicherheit

  • CSRF-Tokens auf allen Formularen
  • Callback-Tokens: HMAC-SHA256, 2h gültig, einmalig verwendbar
  • XXE-Schutz: LIBXML_NONET | LIBXML_NOENT
  • Passwörter verschlüsselt via dolEncrypt/dolDecrypt
  • Testmodus als Standard (IDSCONNECT_TESTMODE=1)
  • Live-Modus erfordert Bestätigung

Sonepar-Schnittstellen

Sonepar unterstützt 3 Schnittstellen:

  1. IDS - XML-basiertes Punchout (das was wir implementiert haben)
  2. OCI - SAP Open Catalog Interface, POST-Felder NEW_ITEM-* (ebenfalls implementiert)
  3. UGL - ÜberGabeSchnittstelleLang, FTP-basierter Dokumentenaustausch (Angebote, Bestellungen, Lieferscheine, Rechnungen) - nicht implementiert

Architektur

WKE-Flow (Warenkorb empfangen)

1. User klickt "Zum Shop" in Dolibarr
2. launch.php generiert HTML-Formular mit:
   - Shop-URL als action
   - USERID, PASSWORT, AESSION (WKE)
   - HOOKURL (callback.php?token=...)
3. Browser submitted Formular an Großhändler-Shop
4. User wählt Artikel im Shop
5. Shop sendet Warenkorb per POST an HOOKURL
6. callback.php empfängt, parst, speichert
7. Callback-Seite zeigt Ergebnis + Link zu cart_review.php
8. cart_review.php: Artikel prüfen → Lieferantenbestellung erstellen

Preisberechnung mit PriceBasis

Im Elektrogroßhandel werden Preise oft pro Preiseinheit (PE) angegeben:

PriceBasis=100 → NetPrice gilt für 100 Stück
Einzelpreis pro Stück = NetPrice / PriceBasis
Gesamtpreis = Qty * (NetPrice / PriceBasis)

Beispiel: 100 Stk Stoßverbinder
  NetPrice=16.88, PriceBasis=100
  → Stückpreis = 16.88 / 100 = 0.1688€
  → Gesamt = 100 * 0.1688 = 16.88€

Datenbank-Tabellen

  • llx_idsconnect_supplier - Großhändler mit URL, Login, Passwort (verschlüsselt)
  • llx_idsconnect_log - Transaktionslog mit Status, XML, Response-JSON, Token

Konfiguration

Dolibarr-Einstellungen (Schlüssel)

Schlüssel Beschreibung Standard
IDSCONNECT_TESTMODE Testmodus aktiv 1
IDSCONNECT_PUBLIC_URL Öffentliche URL für Callback (leer)
IDSCONNECT_LOG_ENABLED Logging aktiviert 1
IDSCONNECT_WKS_WARN_QTY WKS Warn-Menge 0
IDSCONNECT_WKS_WARN_VALUE WKS Warn-Wert 0
IDSCONNECT_WKS_PIN PIN für WKS (verschlüsselt) (leer)

Sonepar-Konfiguration

  • URL: https://www.sonepar.de/punchout/v1/ids/setup?OrganizationId=12
  • Benutzer: ids
  • Kundennummer: 100184
  • IDS-Version: 2.0