dolibarr.idsconnect/CHANGELOG.md
data f1e5a47674 IDS Connect v3.1 - Preis-Vergleich & Produktmatching-Fix
Kritische Bugfixes:
- FIX: Produktmatching korrigiert (qty→quantity, status→tosell in SQL)
  Vorher wurden alle Artikel als Freitext importiert, jetzt korrekte
  Verknüpfung mit Dolibarr-Produkten über product_fournisseur_price

Neue Features:
- FEAT: Sonepar NetPrice-Heuristik implementiert
  Erkennt automatisch ob NetPrice für PriceBasis (IDS-Standard) oder
  Order-Qty (Sonepar-Variante) ist. 2-Pass-Algorithmus vergleicht beide
  Interpretationen mit DB-Preis und wählt korrekte aus.
  Löst +100% Preisabweichungs-Problem bei Sonepar-Warenkörben.

- FEAT: Preis-Vergleich in cart_review.php und tab_supplierorder.php
  Zeigt Abweichungen zwischen Shop-Preisen und gespeicherten Dolibarr-Preisen
  mit farbiger Markierung (rot >10%, gelb 2-10%, grün ≤2%)
  Manuelle Preis-Aktualisierung über Checkboxen (keine Automatik)

- Admin-Option IDSCONNECT_PRICE_UPDATE_ENABLED mit konfigurierbarem Schwellwert
- Übersetzungen für de_DE und en_US erweitert

Dateien:
- class/idsconnect.class.php: matchProducts() qty→quantity Fix
- cart_review.php: Heuristik + Preis-Vergleich UI
- tab_supplierorder.php: Preis-Vergleich für Bestellungen
- admin/setup.php: Neue Preis-Update-Optionen
- CHANGELOG.md: Dokumentation v2.9 und v3.1

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-12 12:27:37 +01:00

324 lines
14 KiB
Markdown
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
---
## 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.qty``pfp.quantity` ersetzt in:
- [class/idsconnect.class.php:578](class/idsconnect.class.php#L578) - matchProducts() SELECT Query
- [class/idsconnect.class.php:589](class/idsconnect.class.php#L589) - $obj->qty → $obj->quantity
- [tab_supplierorder.php:154,177](tab_supplierorder.php#L154) - Preis-Vergleich Queries
- **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 = 1``p.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:
```xml
<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