SW Shopware 6 Mittel

DataFirefly Odoo Konnektor — Installations- und Konfigurationsanleitung

Verbinden Sie Shopware 6.6 / 6.7 mit Odoo 12 → 18 über natives XML-RPC. Installation, API-Schlüssel-Setup, Synchronisationsrichtungen, geplante Aufgaben und Fehlerbehebung.

Aktualisiert Modulversion 1.0.0

Diese Anleitung deckt Installation, Konfiguration und tägliche Nutzung des Plugins DataFirefly Odoo Connector für Shopware 6.6 und 6.7 ab. Am Ende synchronisiert Ihr Shop Produkte, Lagerbestand, Kunden und Bestellungen mit Ihrer Odoo-Instanz über natives XML-RPC — ohne externe Abhängigkeit und ohne Drittanbieter-API-Aufpreis.

Überblick

Das Plugin baut eine bidirektionale Brücke zwischen Shopware und Odoo auf, indem es direkt das XML-RPC-Protokoll von Odoo (seit Version 8 stabil) spricht. Kein Modul auf der Odoo-Seite, keine kostenpflichtige Middleware, kein SaaS-Mittelsmann.

Entität Odoo → Shopware (pull) Shopware → Odoo (push)
Produkte (product.template)
Lagerbestand (qty_available / free_qty)
Kategorien (product.category)
Kunden (res.partner) ✅ mit Unteradressen
Bestellungen (sale.order) ✅ mit optionaler Bestätigung und Rechnung

Voraussetzungen

  • Shopware 6.6.x oder 6.7.x (alle Minor-Versionen).
  • PHP 8.2, 8.3 oder 8.4.
  • PHP-Erweiterungen: curl, xml, simplexml (auf praktisch allen Hostern standardmäßig vorhanden).
  • Odoo 12, 13, 14, 15, 16, 17 oder 18, Community oder Enterprise. Odoo.sh, Odoo Online (SaaS) und selbstgehostete Instanzen funktionieren gleichermaßen.
  • Ein dedizierter Odoo-Benutzer für die API (empfohlen) mit Lese-/Schreibrechten auf den verwendeten Modellen (product.template, product.product, res.partner, sale.order, stock.warehouse, product.category, res.country, account.tax).

Installation

Über das Admin-Upload

  1. Laden Sie DfOdooConnector-v1.0.0.zip aus Ihrem Kundenkonto herunter.
  2. In der Shopware-Administration: Erweiterungen → Meine Erweiterungen → Erweiterung hochladen.
  3. Wählen Sie das ZIP aus und klicken Sie auf Installieren.
  4. Aktivieren Sie die Erweiterung über den Schalter.

Per SSH-Konsole

cd /pfad/zu/shopware
cp DfOdooConnector-v1.0.0.zip custom/plugins/
cd custom/plugins && unzip DfOdooConnector-v1.0.0.zip
sudo -u www-data setsid php bin/console plugin:refresh
sudo -u www-data setsid php bin/console plugin:install --activate DfOdooConnector
sudo -u www-data setsid php bin/console cache:clear

Bauen Sie die Administration neu, um das Vue-3-Modul zu laden:

sudo -u www-data setsid php bin/build-administration.sh
Hinweis — Die Installation erstellt zwei Tabellen: df_odoo_mapping (persistente Shopware ↔ Odoo-Zuordnungen) und df_odoo_log (Operationsjournal). Es wird keine bestehende Tabelle verändert.

Konfiguration auf der Odoo-Seite

Dedizierten Benutzer anlegen

Wir empfehlen dringend, einen dedizierten Odoo-Benutzer für die Integration anzulegen, anstatt einen persönlichen Administratoraccount zu verwenden. So lassen sich die Aktionen des Konnektors leichter auditieren und sein Zugriff unabhängig widerrufen.

  1. In Odoo: Einstellungen → Benutzer und Unternehmen → Benutzer.
  2. Legen Sie einen Benutzer beispielsweise namens Shopware Bridge an.
  3. Vergeben Sie die nötigen Rechte: Lager (Benutzer), Verkauf (Administrator), Buchhaltung (Benutzer, falls Sie die Rechnungserstellung aktivieren), Kontakte (Benutzer).

API-Schlüssel generieren

  1. Melden Sie sich mit diesem neuen Benutzer in Odoo an.
  2. Klicken Sie oben rechts auf den Avatar → Präferenzen.
  3. Reiter KontoAPI-SchlüsselNeuer API-Schlüssel.
  4. Geben Sie einen aussagekräftigen Namen ein (z. B. Shopware Connector) und kopieren Sie den generierten Wert.
Wichtig — Der API-Schlüssel wird nur einmal angezeigt. Falls Sie ihn verlieren, müssen Sie einen neuen generieren. Speichern Sie ihn in einem Passwortmanager, bevor Sie den Dialog schließen.

Konfiguration auf der Shopware-Seite

Verbindungsdaten eintragen

In der Shopware-Administration: Einstellungen → System → Plugins → Df Odoo → Einstellungen oder über das Seitenmenü Einstellungen → Df Odoo → Einstellungen.

  • Odoo URL: vollständige URL Ihrer Instanz ohne abschließenden Schrägstrich, z. B. https://meinkonto.odoo.com.
  • Datenbankname: in der Odoo-URL nach ?db= sichtbar oder unter Einstellungen → Technisch → Datenbank.
  • Benutzer: Login des dedizierten Benutzers, meist die E-Mail-Adresse.
  • Odoo API-Schlüssel: im vorherigen Schritt kopierter Wert.
  • Timeout: standardmäßig 30 Sekunden, in den meisten Fällen ausreichend.

Verbindung testen

Klicken Sie oben rechts auf Verbindung testen. Wenn alles korrekt ist, zeigt eine grüne Benachrichtigung die Odoo-Version und die Benutzerkennung (uid) an. Schlägt die Verbindung fehl, wird die von Odoo zurückgegebene Fehlermeldung unverändert angezeigt.

Tipp — Der Verbindungstest lässt sich auch von der Konsole aufrufen, um eine Health-Check zu skripten:
curl -X POST -H "Authorization: Bearer ADMIN_TOKEN" https://ihrshopware.com/api/_action/df-odoo/test-connection

Synchronisationsrichtungen

Jede Entität hat ihren eigenen Selektor: deaktiviert, Odoo → Shopware (pull), Shopware → Odoo (push) oder bidirektional. Die Standardwerte sind:

  • Produkte: bidirektional
  • Lagerbestand: Odoo → Shopware (Odoo ist die Wahrheitsquelle)
  • Kunden: Shopware → Odoo
  • Bestellungen: Shopware → Odoo
  • Kategorien: deaktiviert (je nach Organisation manuell aktivieren)

Produktsynchronisation

Zuordnungsstrategien

Drei Strategien sind konfigurierbar:

  • SKU (empfohlen): Shopware productNumber ↔ Odoo default_code.
  • Odoo-ID: stützt sich ausschließlich auf die persistente Zuordnungstabelle. Nützlich, wenn Ihre SKUs unbeständig sind.
  • Barcode (EAN): Shopware ean ↔ Odoo barcode. Erfordert EANs auf beiden Seiten.

Einmal verknüpft, bleiben zwei Produkte über die Tabelle df_odoo_mapping verknüpft, selbst wenn sich die SKU später ändert.

Pull aus Odoo

Die geplante Aufgabe liest product.template-Datensätze, die seit dem letzten Lauf geändert wurden (Feld write_date), und legt die entsprechenden Shopware-Produkte an oder aktualisiert sie. Synchronisierte Felder: Name, SKU, Verkaufspreis, Einstandspreis, Kurzbeschreibung, Langbeschreibung, Gewicht, Volumen, Aktiv-Status, Kategorie, Steuern.

Push nach Odoo

Aktive Shopware-Hauptprodukte (mit parentId = null) werden als product.template vom Typ product (lagerbare Ware) an Odoo gesendet. Shopware-Varianten werden unter ihrem Hauptprodukt gebündelt.

Änderungserkennung — Vor jeder Schreiboperation wird ein SHA-1-Hash des Inhalts mit dem im Mapping gespeicherten verglichen. Hat sich nichts geändert, wird der Schreibvorgang übersprungen und die Operation als skipped protokolliert. So wird Odoo bei aufeinanderfolgenden Cron-Läufen nicht überlastet.

Lagerbestandssynchronisation

Der Lagerbestand wird immer aus Odoo gezogen (nie umgekehrt). Alle 15 Minuten liest die geplante Aufgabe product.product-Varianten in Stapeln von 100 nach übergeordneter Template-ID, aggregiert qty_available oder free_qty (global konfigurierbar) und aktualisiert das Feld stock jedes Shopware-Produkts in einer einzigen DAL-Anfrage.

qty_available vs. free_qtyqty_available spiegelt den physischen Bestand im Lager wider. free_qty zieht bereits auf nicht ausgelieferten Bestellungen reservierte Mengen ab. free_qty ist für einen Online-Shop in der Regel vorzuziehen, da Überverkäufe vermieden werden.

Kategoriensynchronisation

Standardmäßig deaktiviert. Aktivieren Sie sie, wenn Ihr Kategoriebaum mit dem von Odoo synchron bleiben soll. Die Hierarchie parent_id wird auf beiden Seiten erhalten. Wie bei Produkten verhindert ein Inhalts-Hash unnötige Schreibvorgänge.

Kundensynchronisation

Shopware-Kunden werden als Odoo-res.partner mit Folgendem gepusht:

  • Deduplizierung per E-Mail: Vor jeder Anlage wird ein bestehender Partner mit derselben E-Mail und parent_id = false gesucht. Wird einer gefunden, wird er aktualisiert statt dupliziert.
  • company_type: company, wenn das Feld Unternehmen der Rechnungsadresse ausgefüllt ist, sonst person.
  • Unteradressen: Die Standardrechnungsadresse wird als Unterpartner mit type='invoice' angelegt, die Standardlieferadresse als Unterpartner mit type='delivery'.
  • Innergemeinschaftliche USt-IdNr.: wird auf das Feld vat des Hauptpartners übernommen.
  • Land und Region: per ISO-Code mit In-Memory-Cache pro Anfrage aufgelöst.

Bestellsynchronisation

In Echtzeit beim Checkout

Ist die Option Jede Bestellung beim Auslösen pushen aktiviert, lauscht ein Event-Subscriber auf CheckoutOrderPlacedEvent und überträgt die Bestellung unmittelbar nach Checkout-Abschluss an Odoo. Der Kunde wird bei Bedarf in Odoo angelegt (über die Kundensynchronisation), anschließend wird die Bestellung als sale.order mit folgendem erzeugt:

  • partner_id über die Kundenzuordnung aufgelöst.
  • order_line in Odoo-Tuple-Syntax: [0, 0, {name, product_uom_qty, price_unit, product_id}].
  • Eine zusätzliche Position für Versandkosten, wenn die Versand-totalPrice größer null ist.
  • company_id, warehouse_id, pricelist_id gemäß den konfigurierten Standardwerten.
Der Checkout wird nie blockiert — Ist Odoo nicht erreichbar, wird der Fehler in df_odoo_log protokolliert und die Bestellung innerhalb von 10 Minuten von der geplanten Aufgabe df_odoo.order_sync erneut versucht, welche die nicht zugeordneten Bestellungen der letzten 7 Tage scannt.

Statusfilter

Die Einstellung Bestellstatus-Filter schränkt ein, welche Bestellungen gepusht werden:

  • Alle: jede ausgelöste Bestellung wird gesendet (für B2C mit sofortiger Zahlung empfohlen).
  • Nur bezahlt: Nur Bestellungen mit Zahlungsstatus paid werden gepusht. Verhindert, dass abgebrochene Warenkörbe mit manueller Zahlung Odoo verschmutzen.
  • Bezahlt oder versendet: Pusht zusätzlich Bestellungen, die vor der Zahlung versendet wurden (B2B mit Zahlungsfristen).

Automatische Bestätigung und Rechnung

Zwei Optionen steuern, was auf der Odoo-Seite passiert, sobald die Bestellung angelegt ist:

  • Bestellung bestätigen: ruft action_confirm auf der sale.order auf, die direkt in den Zustand bestätigte Bestellung wechselt, statt als Angebot stehen zu bleiben.
  • Rechnung erstellen: ruft _create_invoices auf, um sofort eine validierte Rechnung zu erzeugen. Die ID der erstellten Rechnung wird als Mapping vom Typ invoice gespeichert.

Multi Sales Channel

Alle Plugin-Einstellungen können pro Sales Channel überschrieben werden. Oben auf der Seite Einstellungen erlaubt der native Shopware-Selektor das Umschalten zwischen Alle Channels und einem bestimmten Channel.

Typische Anwendungsfälle:

  • Ein B2C-Channel, der an ein Haupt-Odoo pusht, und ein B2B-Channel, der an ein separates Odoo pusht.
  • Ein Produktions-Channel mit Richtung push und ein Staging-Channel mit Richtung deaktiviert.
  • Unterschiedliche Odoo-IDs (Warehouse, Sales Team, Pricelist) je Channel.

Geplante Aufgaben

Interner Name Frequenz Aktion
df_odoo.product_sync 1 Stunde Pull und Push von Produkten gemäß der konfigurierten Richtung. Pull betrachtet nur seit -2h geänderte Datensätze.
df_odoo.stock_sync 15 Minuten Pull des Lagerbestands aus Odoo für alle bereits zugeordneten Produkte.
df_odoo.customer_sync 1 Stunde Push aktiver, noch nicht zugeordneter Kunden (max. 100 pro Lauf).
df_odoo.order_sync 10 Minuten Push der nicht zugeordneten Bestellungen der letzten 7 Tage (max. 50 pro Lauf).

Eine Aufgabe von der Konsole erzwingen:

sudo -u www-data setsid php bin/console scheduled-task:run-single df_odoo.product_sync
Shopware-Worker — Damit geplante Aufgaben automatisch auslösen, muss der Shopware Messenger-Worker laufen (Cron messenger:consume oder systemd-Unit). Prüfen Sie in Einstellungen → System → Warteschlange, dass scheduled_task regelmäßig konsumiert wird.

Admin-Modul

Ein Bereich Df Odoo erscheint unter Einstellungen → Plugins mit vier Seiten.

Dashboard

Live-Zähler (aktive Zuordnungen pro Entität, Aktivität der letzten 24h pro Status), manuelle Sync-Buttons pro Entität (Pull und Push), Verbindungsstatusbanner, Liste der letzten Fehler und Verknüpfungen zu den anderen Seiten.

Einstellungen

Vollständiges Formular mit Sales-Channel-Auswahl. Buttons Verbindung testen und Speichern in der Aktionsleiste.

Logs

Jede Operation wird in df_odoo_log mit ihrem Status (success, error, warning, skipped), Richtung, Entität, Dauer in Millisekunden und vollständiger Nachricht protokolliert. Kombinierbare Filter nach Status, Entitätstyp und Richtung. Serverseitige Paginierung.

Debug-ModusSkipped-Operationen werden nur dann ins Journal geschrieben, wenn der Debug-Modus in den Einstellungen aktiviert ist. Verwenden Sie ihn punktuell zur Diagnose und deaktivieren Sie ihn im Produktivbetrieb, um die Tabelle nicht aufzublähen.

Zuordnungen

Lesende Ansicht auf die Tabelle df_odoo_mapping mit Suche, Filter nach Entitätstyp und Sortierung nach letztem Synchronisationsdatum. Praktisch, um zu prüfen, ob ein bestimmtes Produkt der erwarteten Odoo-ID zugeordnet ist.

Admin REST-API

Alle Endpunkte erfordern eine Standard-Admin-Authentifizierung (Bearer-Token).

Methode Endpunkt Parameter
POST /api/_action/df-odoo/test-connection salesChannelId (optional)
POST /api/_action/df-odoo/sync/products direction=pull|push, salesChannelId
POST /api/_action/df-odoo/sync/stock salesChannelId
POST /api/_action/df-odoo/sync/customers salesChannelId
POST /api/_action/df-odoo/sync/orders salesChannelId, limit (1-500)
POST /api/_action/df-odoo/sync/categories direction=pull|push
GET /api/_action/df-odoo/stats
GET /api/_action/df-odoo/logs status, entityType, direction, page, perPage

Beispielaufruf zum Erzwingen eines Produkt-Pushs:

curl -X POST 
  -H "Authorization: Bearer ADMIN_TOKEN" 
  -d "direction=push" 
  https://ihrshopware.com/api/_action/df-odoo/sync/products

Tabellen und gespeicherte Daten

Das Plugin erstellt zwei MySQL-Tabellen:

  • df_odoo_mapping — persistente Zuordnungen (Shopware-ID ↔ Odoo-ID) mit Synchronisations-Hash und optionalem Payload. Eine Zeile ist eindeutig auf (Entitätstyp, Shopware-ID) und auf (Entitätstyp, Odoo-ID).
  • df_odoo_log — Operationsjournal mit Status, Dauer, Nachricht, Payload, Sales-Channel-ID.

Es wird keine Standardtabelle von Shopware verändert.

Deinstallation

Aus der Administration: Erweiterungen → Meine Erweiterungen → Df Odoo → Deinstallieren.

Ein Dialog bietet zwei Optionen:

  • Benutzerdaten behalten aktiviert: Die Tabellen df_odoo_mapping und df_odoo_log sowie die Systemeinstellungen bleiben erhalten. Praktisch für eine spätere Neuinstallation.
  • Benutzerdaten behalten deaktiviert: Beide Tabellen werden bei der Deinstallation gelöscht (DROP TABLE). Die Odoo-Instanz wird nie angerührt.

Fehlerbehebung

„Odoo-Konfiguration unvollständig“ beim Verbindungstest

Eines der vier Pflichtfelder (URL, Datenbank, Benutzer, API-Schlüssel) ist leer. Vergewissern Sie sich, dass der richtige Sales Channel vor dem Speichern ausgewählt war.

„401 Unauthorized“ oder „access denied“

Der API-Schlüssel wurde auf der Odoo-Seite widerrufen oder der Benutzer hat nicht die erforderlichen Rechte auf das Zielmodell. Generieren Sie einen neuen API-Schlüssel und prüfen Sie die Odoo-Rechte des Benutzers (insbesondere Lager → Benutzer und Verkauf → Administrator).

„Verbindung verweigert“ oder Timeout

Die Odoo-URL ist vom Shopware-Server aus nicht erreichbar. Stellen Sie sicher, dass die Firewall ausgehende HTTPS-Verbindungen zur Odoo-Domain erlaubt. Erhöhen Sie das Timeout, falls Ihre Odoo-Instanz langsam antwortet.

Produkte werden nicht synchronisiert

Prüfen Sie das Journal (Seite Logs) auf Fehlereinträge. Aktivieren Sie den Debug-Modus, um auch skipped-Operationen zu erfassen und herauszufinden, ob der Inhalts-Hash bedeutet, dass sich tatsächlich nichts geändert hat.

Bestellungen werden beim Checkout nicht gepusht

Stellen Sie sicher, dass die Option Jede Bestellung beim Auslösen pushen aktiviert ist und die Richtung Bestellungen auf Shopware → Odoo steht. Steht der Statusfilter auf Nur bezahlt und ist die Zahlung asynchron, pusht die geplante Aufgabe die Bestellung wenige Minuten nach dem Zahlungseingang.

Bekannte Einschränkungen

  • Odoo-Variantenattribute (product.attribute) werden noch nicht automatisch zugeordnet. Shopware-Varianten werden als Odoo-Hauptprodukte (product.template) gebündelt. Manuell in Odoo angelegte Varianten bleiben über ihr Parent-Template korrekt verknüpft. Eine native Verwaltung ist für Version 1.1 geplant.
  • Rabatte auf Bestellpositionen werden als angepasster price_unit gemeldet, nicht als Odoo-Feld discount.
  • Shopware-Zahl- und Versandarten werden nicht auf Odoo-journal_id abgebildet — es werden die Odoo-Standardwerte verwendet.

Support

Bei Fragen kontaktieren Sie das DataFirefly-Team über das Kontaktformular auf datafirefly.com. Bitte hängen Sie den Journal-Export an (Seite Logs → Export-Button folgt) oder zumindest einen Screenshot der fehlgeschlagenen Zeile sowie die genauen Versionen von Shopware, PHP und Odoo.

War diese Seite hilfreich?

Immer noch nicht weiter? Support kontaktieren