Einführung
In Odoo bilden Modelle das Gerüst für alle Geschäftsdaten. Ob Angebote, Rechnungen oder Kontakte – jede Information wird in einem Modell strukturiert und in der Datenbank abgelegt.
Für Entwickler und Anwenderberater sind Modelle unverzichtbar: Sie legen Felder, Beziehungen und die Geschäftslogik fest und sind damit das Rückgrat der Odoo‑Datenarchitektur.
Im Mittelpunkt dieses Beitrags steht ein zentrales Modell des Verkaufsmoduls: sale.order.line. Ob Sie Erweiterungen entwickeln, externe Systeme anbinden oder Preisprozesse konfigurieren — dieses Modell begegnet Ihnen immer wieder.
Was hinter dem sale.order.line‑Modell steckt
Das sale.order.line‑Modell bildet einzelne Positionen auf Angebot oder Auftrag ab. Jede Position beschreibt in der Regel ein Produkt inklusive Menge, Preis und Steuern.
Das Modell gehört zum Verkaufsmodul (sale) und nutzt unter anderem analytic.mixin, damit Projektkosten und Zeiten verknüpft werden können. Wenn ein Produkt in ein Angebot gelegt wird, erzeugen Sie damit automatisch einen sale.order.line‑Datensatz.
Die Definition liegt im sale‑Modul; weitere Module ergänzen das Modell über die Odoo‑Vererbung. Beispiele: sale_stock erweitert um lieferbezogene Felder, sale_margin um Margenberechnungen — so bleibt die Kernstruktur konsistent und erweiterbar.
Wichtige Felder im Modell
Nachfolgend die Felder, die Sie als Anwender oder Entwickler am häufigsten sehen und nutzen werden. Ein Verständnis dieser Felder erleichtert Konfiguration, Entwicklung und Fehlersuche.
1. order_id
Typ: Many2one (sale.order). Pflichtfeld. Verweist auf den übergeordneten Auftrag. Die Verbindung stellt sicher, dass jede Position einem Auftrag zugeordnet ist; Löschung des Auftrags entfernt auch die Positionen (Cascade).
2. sequence
Typ: Integer. Standard 10. Steuert die Anzeige‑Reihenfolge der Positionen im Auftrag. Wird genutzt, um Abschnitte, Hinweise und Produktzeilen zu sortieren.
3. company_id
Typ: Many2one (res.company). Vom order_id abgeleitet. Relevant für Multi‑Company‑Regeln und Zugriffssteuerung.
4. currency_id
Typ: Many2one (res.currency). Vom order_id abgeleitet. Legt die Währung aller Geldfelder in der Position fest und sorgt für korrekte Preisberechnung.
5. order_partner_id
Typ: Many2one (res.partner). Vom order_id abgeleitet. Der Kunde — wichtig für Preislisten, Zahlungskonditionen und Steuerschlüssel.
6. salesman_id
Typ: Many2one (res.users). Vom order_id abgeleitet. Zuständiger Vertriebsmitarbeiter, relevant für Provisionen und Reporting.
7. state
Typ: Selection. Vom order_id abgeleitet. Status des Auftrags (z. B. draft, sent, sale, done, cancel) und Grundlage dafür, welche Felder bearbeitbar sind.
8. display_type
Typ: Selection. Mögliche Werte: line_section oder line_note. Kennzeichnet eine Überschrift oder Anmerkung — dann handelt es sich nicht um eine Produktposition und Produktfelder bleiben leer.
9. is_downpayment
Typ: Boolean. Markiert Anzahlungen; solche Positionen werden separat fakturiert.
10. is_expense
Typ: Boolean. Gilt für Positionen, die aus Spesen oder Lieferantenrechnungen stammen — wichtig für Kostenverfolgung in Projekten.
11. product_id
Typ: Many2one (product.product). Das verkaufte Produkt. Die Auswahl ist in der Regel auf verkaufbare Produkte eingeschränkt; für Produktpositionen ist dieses Feld erforderlich.
12. product_template_id
Typ: Many2one (product.template). Wird aus product_id berechnet. Wichtig für den Produktkonfigurator und Variantenwahl.
13. name
Typ: Text. Positionsbeschreibung. Wird aus Produktdaten und benutzerdefinierten Attributen generiert und enthält Varianteninformationen, wenn nötig.
14. product_uom_qty
Typ: Float. Pflichtfeld. Bestellte Menge. Default 1.0. Kann durch Verpackungseinheiten beeinflusst werden.
15. product_uom
Typ: Many2one (uom.uom). Mengeneinheit. Standardwert vom Produkt; relevant für Mengenerfassung und Preisberechnung.
16. tax_id
Typ: Many2many (account.tax). Auf die Position angewendete Steuern. Wird aus Produkt, Verkäuferland und steuerlicher Position berechnet.
17. price_unit
Typ: Float. Pflichtfeld. Preis pro Einheit (bezogen auf product_uom). Wird aus Preislisten oder Produkt festgelegt, lässt sich aber manuell überschreiben.
18. discount
Typ: Float. Rabatt in Prozent. Wird auf price_unit vor der Steuerberechnung angewandt.
19. price_subtotal
Typ: Monetary. Zwischensumme vor Steuern. Berechnet aus Menge, Einheitspreis und Rabatt.
20. price_tax
Typ: Float. Gesamtsteuerbetrag. Ermittelt aus price_subtotal und tax_id.
21. price_total
Typ: Monetary. Gesamtbetrag inklusive Steuern. Relevante Größe für die Fakturierung.
22. product_packaging_id
Typ: Many2one (product.packaging). Optionale Verpackung (z. B. Karton mit 12 Stück). Kann die Mengensteuerung beeinflussen.
23. customer_lead
Typ: Float. Lieferzeit in Tagen — Zeitraum zwischen Auftragsbestätigung und Versand; Grundlage für Lieferterminberechnung.
24. qty_delivered
Typ: Float. Gelieferte Menge. Wird durch Lagerbewegungen aktualisiert oder manuell gesetzt; wichtig für Teilfakturierung.
25. qty_invoiced
Typ: Float. Bereits in Rechnung gestellte Menge. Wird aus Rechnungszeilen berechnet.
26. qty_to_invoice
Typ: Float. Verbleibende Menge, die noch zu fakturieren ist. Ergebnis aus qty_delivered und qty_invoiced.
27. invoice_status
Typ: Selection. Werte wie upselling, invoiced, to invoice, no — zeigt den Fakturierungsstatus der Position an.
28. invoice_lines
Typ: Many2many (account.move.line). Verknüpfung zu den Rechnungszeilen, die aus dieser Auftragsposition entstanden sind — wichtig für Nachvollziehbarkeit.
29. create_date
Typ: Datetime. Zeitpunkt der Erstellung. Wird automatisch von Odoo verwaltet.
30. write_date
Typ: Datetime. Zeitpunkt der letzten Änderung. Nützlich für Audits und Synchronisationen.
Einsatz in typischen Geschäftsabläufen
1. Angebot und Auftrag
Wenn ein Vertriebsmitarbeiter ein Angebot erstellt, fügt er Produktpositionen hinzu — jede einzelne wird als sale.order.line angelegt. Dort sehen Sie Menge, Preis, Rabatt und Zwischensumme; nach Kundenbestätigung wird das Angebot zum Auftrag.
2. Preislisten und Rabatte
Preislisten steuern üblicherweise den price_unit und können komplexe Regeln wie Staffelpreise oder kundenspezifische Konditionen abbilden. Rabatte werden als Prozentwert auf der Position verwaltet.
3. Lieferung und Fakturierung
Mit erfolgter Lieferung aktualisiert das System qty_delivered. Die Fakturierung kann pro Lieferung oder gesamthaft erfolgen; invoice_status zeigt an, welche Mengen noch offen sind.
4. Projekte und Dienstleistungen
Bei Dienstleistungsprodukten sind Positionen oft mit Projektaufgaben und Timesheets verknüpft. Durch die analytic.mixin‑Erweiterung lassen sich Kosten auf Projekte zusammenführen.
5. E‑Commerce und Kundenportal
Im Webshop landen Warenkörbe als Verkaufsaufträge; jede Zeile des Warenkorbs wird zu einer sale.order.line. Der Produktkonfigurator nutzt dabei product_template_id und Attribute zur Variantenbildung.
Wie Entwickler das Modell erweitern
Entwickler erweitern sale.order.line mit verschiedenen Mustern. Kernwerkzeug ist die Odoo‑Modellvererbung.
Modellvererbung
Mit _inherit = 'sale.order.line' erweitern Sie das Modell: neue Felder hinzufügen, Methoden überschreiben oder Validierungen ergänzen. Änderungen bleiben in Ihrem Modul getrennt und erleichtern spätere Upgrades.
Neue Felder hinzufügen
Ergänzen Sie Felder im geerbten Modell mit passenden Typen: Char, Many2one, Boolean, Integer, Text, Selection. Denken Sie an unternehmensabhängige Felder bei Multi‑Company‑Setups.
Python‑Erweiterungen
Überschreiben Sie Berechnungs‑Methoden wie _compute_price_unit oder _compute_price_subtotal, oder hooken Sie create/write ein. Rufen Sie super() auf, und definieren Sie Abhängigkeiten für computed‑Felder korrekt.
Odoo Studio
Mit Odoo Studio lassen sich Felder ohne Code ergänzen — ideal für schnelle Anpassungen. Bei komplexer Geschäftslogik oder Update‑Sicherheit sind eigene Module jedoch robuster.
Best Practices
- Nutzen Sie display_type bewusst für Überschriften und Hinweise statt Platzhalterprodukte — das verhindert verfälschte Reports und Validierungsfehler.
- Bei API‑Integrationen legen Sie Positionen am besten über das order_line‑Feld des sale.order an und verwenden die korrekte Command‑Syntax, sodass Verknüpfungen sauber entstehen.
- Achten Sie auf Datenintegrität und SQL‑Constraints: Produktpositionen benötigen product_id und product_uom, Abschnitts‑ oder Hinweiszeilen müssen display_type gesetzt haben.
- Für kundenspezifische Preise nutzen Sie, wenn möglich, die Preislistenmechanik. Override von Berechnungslogik nur, wenn die Standardregeln nicht abbildbar sind.
- Benennen Sie eigene Felder mit x_ oder modulbezogenem Präfix, um Namenskonflikte mit zukünftigen Odoo‑Versionen zu vermeiden.
Häufige Fehlerquellen
- Erstellen Sie Positionen nicht ohne order_id. Das Feld ist erforderlich — Positionen gehören immer in den Kontext eines Auftrags.
- Verwechseln Sie nicht product_id mit product_template_id: Für tatsächliche Produktzeilen ist product_id maßgeblich; product_template_id wird vor allem im Konfigurator‑Flow genutzt, um Varianten auszuwählen.
- Änderungen an price_unit oder discount nach bereits erfolgter Fakturierung (qty_invoiced > 0) führen leicht zu Inkonsistenzen — vermeiden Sie dies oder dokumentieren Sie Anpassungen sorgsam.
- Überschreiben Sie Kernmethoden niemals ohne super() aufzurufen. Das kann andere Module stören und künftige Updates brechen.
- Vergessen Sie nicht, display_type für Abschnitts‑ oder Hinweiszeilen zu setzen — sonst behandelt Odoo die Zeile als Produktposition, was zu Validierungsfehlern führt.
Fazit
Das sale.order.line‑Modell ist das Herzstück des Verkaufs in Odoo: Es hält alle Positionen eines Angebots oder Auftrags fest. Ein gutes Verständnis seiner Felder und Erweiterungsmöglichkeiten vereinfacht Konfiguration, Individualisierung und Integration erheblich.
Ob Sie Prozesse modellieren oder Erweiterungen entwickeln — fundiertes Wissen über sale.order.line vermindert Fehlkonfigurationen und spart Entwicklungszeit.
Brauchen Sie Unterstützung bei Ihrer Odoo‑Einführung?
Dasolo unterstützt Unternehmen bei der Einführung, Anpassung und Optimierung von Odoo. Wir sind spezialisiert auf API‑Integration und individuelle Odoo‑Entwicklung und kennen die Datenarchitektur und Modelle wie sale.order.line sehr gut.
Wenn Sie Hilfe bei der Odoo‑Einführung, bei individuellen Modulen oder Integrationen benötigen, sprechen Sie uns an. Demo vereinbaren um Ihr Projekt zu besprechen.