Wstęp
W Odoo każdy element biznesowych danych — zamówienia, faktury, kontrahenci — ma swoje miejsce w strukturze danych zwanej modelem. Modele określają, jakie informacje są przechowywane i jak są powiązane w bazie.
Dla konsultantów funkcjonalnych i programistów znajomość modeli Odoo to podstawa. To one określają pola, relacje między rekordami oraz logikę biznesową, którą system egzekwuje.
Ten tekst koncentruje się na jednym z kluczowych modeli sprzedażowych: sale.order.line. Niezależnie czy tworzysz moduły, integrujesz systemy czy konfigurujesz cenniki — prędzej czy później trafisz na ten model.
Czym jest model sale.order.line
Model sale.order.line odwzorowuje pojedyncze pozycje na ofercie lub zamówieniu sprzedaży. Każdy rekord opisuje zwykle jeden produkt: ilość, cenę, podatki i ewentualne notatki.
Model jest wykorzystywany w module Sales (sale) i dziedziczy np. po analytic.mixin, co umożliwia śledzenie kosztów projektów i powiązanie z timesheetami. Dodanie produktu do oferty tworzy rekord sale.order.line.
Definicja modelu znajduje się w module sale, a inne moduły rozszerzają go przez dziedziczenie modelu Odoo. Przykładowo sale_stock dopisuje pola związane z dostawą, a sale_margin — obliczenia marży. Każdy moduł dopisuje potrzebne funkcje, nie powielając rdzenia.
Najważniejsze pola w modelu
Poniżej znajdziesz przegląd kluczowych pól modelu sale.order.line — ich zrozumienie ułatwi pracę z ofertami i zamówieniami.
1. order_id
Typ: Many2one (sale.order). Pole obowiązkowe. Wskaźnik na zamówienie rodzica — łączy pozycję z dokumentem sprzedaży. Usuwanie zamówienia powoduje skasowanie powiązanych linii (kaskada).
2. sequence
Typ: Integer. Domyślnie 10. Określa kolejność wyświetlania linii na dokumencie — przydatne do sortowania sekcji, notatek i produktów.
3. company_id
Typ: Many2one (res.company). Pole powiązane z order_id. Służy regułom wielofirmowym i kontroli dostępu.
4. currency_id
Typ: Many2one (res.currency). Relacja z order_id. Waluta używana we wszystkich polach pieniężnych na linii — gwarantuje poprawne wartości ceny.
5. order_partner_id
Typ: Many2one (res.partner). Relacja z order_id. Reprezentuje klienta; wpływa na wybór cennika i zasad podatkowych.
6. salesman_id
Typ: Many2one (res.users). Relacja z order_id. Przypisanie handlowca — używane do prowizji i raportów sprzedażowych.
7. state
Typ: Selection. Relacja z order_id. Status zamówienia (np. draft, sent, sale, done, cancel) decyduje, które pola są edytowalne.
8. display_type
Typ: Selection. Wartości: line_section albo line_note. Ustawienie tego pola oznacza, że rekord pełni rolę nagłówka sekcji lub notatki, a nie linii produktowej — pola produktu pozostają puste.
9. is_downpayment
Typ: Boolean. Informuje, czy linia jest zaliczką. Zaliczki fakturowane są oddzielnie.
10. is_expense
Typ: Boolean. True gdy linia pochodzi z kosztu lub rachunku dostawcy — przydatne przy ewidencji kosztów projektów.
11. product_id
Typ: Many2one (product.product). Wskazuje sprzedawany produkt. Domena ogranicza do produktów dostępnych w sprzedaży — wymagane dla linii produktowych.
12. product_template_id
Typ: Many2one (product.template). Pole wyliczane na podstawie product_id. Wykorzystywane przez konfigurator produktu przy wyborze wariantu.
13. name
Typ: Text. Opis pozycji. Zwykle generowany z danych produktu i atrybutów — zawiera szczegóły wariantu, gdy dotyczy.
14. product_uom_qty
Typ: Float. Pole wymagane. Ilość zamawiana. Domyślnie 1.0. Może być powiązana z opakowaniem.
15. product_uom
Typ: Many2one (uom.uom). Jednostka miary. Domyślnie z produktu. Wpływa na ilość i wyliczanie ceny.
16. tax_id
Typ: Many2many (account.tax). Podatki stosowane do linii. Zwykle obliczane na podstawie produktu i pozycji fiskalnej kontrahenta.
17. price_unit
Typ: Float. Pole wymagane. Cena jednostkowa przypisana do jednostki miary. Zazwyczaj pochodzi z cennika lub z karty produktu, ale można ją nadpisać ręcznie.
18. discount
Typ: Float. Procent zniżki. Stosowany względem price_unit przed naliczeniem podatków.
19. price_subtotal
Typ: Monetary. Suma przed podatkiem. Obliczana z ilości, ceny jednostkowej i zniżki.
20. price_tax
Typ: Float. Kwota podatku. Wyliczana na podstawie price_subtotal i tax_id.
21. price_total
Typ: Monetary. Całkowita wartość z podatkiem — kluczowa przy fakturowaniu.
22. product_packaging_id
Typ: Many2one (product.packaging). Opcjonalne opakowanie (np. pudełko po 12). Po ustawieniu może wpływać na jednostki ilości.
23. customer_lead
Typ: Float. Czas realizacji w dniach — odstęp między potwierdzeniem zamówienia a wysyłką, potrzebny do kalkulacji daty dostawy.
24. qty_delivered
Typ: Float. Ilość dostarczona. Aktualizowana przez ruchy magazynowe lub ręcznie — stosowana przy fakturowaniu częściowym.
25. qty_invoiced
Typ: Float. Ilość już zafakturowana. Pole obliczane na podstawie powiązanych linii faktur.
26. qty_to_invoice
Typ: Float. Pozostała do zafakturowania ilość. Wyliczana z qty_delivered i qty_invoiced.
27. invoice_status
Typ: Selection. Wartości: upselling, invoiced, to invoice, no — wskazuje stan fakturowania dla danej linii.
28. invoice_lines
Typ: Many2many (account.move.line). Powiązania z liniami faktur utworzonymi z tej pozycji — istotne dla śledzenia pochodzenia wartości.
29. create_date
Typ: Datetime. Data utworzenia rekordu — automatycznie przez Odoo.
30. write_date
Typ: Datetime. Data ostatniej modyfikacji — przydatna do audytu zmian.
Zastosowanie modelu w procesach biznesowych
1. Oferta i zamówienie sprzedaży
Gdy handlowiec tworzy ofertę, dodaje pozycje produktowe — każda staje się osobnym sale.order.line. Linia zawiera ilość, cenę, rabat i wartość. Po akceptacji przez klienta oferta zamienia się w zamówienie.
2. Cenniki i rabaty
Cennik działa na poziomie linii: price_unit i discount często są wyznaczane przez reguły cennikowe. Obsługiwane są rabaty ilościowe i ceny przypisane do kontrahentów.
3. Dostawa i fakturowanie
Po wysyłce aktualizowane jest qty_delivered. Faktury można wystawiać za całość lub za poszczególne dostawy — pole invoice_status pomaga określić, co jeszcze pozostaje do zafakturowania.
4. Projekt i usługi
W przypadku produktów usługowych linie mogą być powiązane z zadaniami projektowymi i timesheetami. Dzięki analytic.mixin możliwe jest przypisanie kosztów do projektów.
5. E‑commerce i portal
Produkty dodane do koszyka na stronie trafiają jako linie zamówienia — sale.order.line. Konfigurator produktu korzysta z product_template_id i atrybutów, by stworzyć poprawny opis i wariant.
Jak deweloperzy rozszerzają ten model
Deweloperzy rozszerzają sale.order.line kilkoma metodami, z dziedziczeniem modelu jako podstawowym narzędziem.
Dziedziczenie modelu
W module użyj _inherit = 'sale.order.line' by dopisać pola, nadpisać metody lub dodać ograniczenia. Rozszerzenia trzymane w oddzielnym module ułatwiają aktualizacje i utrzymanie.
Dodawanie pól
W klasie dziedziczącej deklaruj nowe pola: Char, Many2one, Boolean, Integer, Text, Selection itd. Przy projektowaniu pamiętaj o polach zależnych od firmy w środowiskach multi‑company.
Rozszerzenia w Pythonie
Nadpisuj metody wyliczające, np. _compute_price_unit lub _compute_price_subtotal, albo dodawaj logikę w create/write. Zawsze wywołuj super(), by nie łamać istniejącej funkcjonalności — uważaj na zależności pól obliczanych.
Odoo Studio
Odoo Studio pozwala na szybkie dodawanie pól bez kodu — dobre do szybkich zmian. Dla złożonej logiki i stabilności przy aktualizacjach lepsze są dedykowane moduły.
Zalecane praktyki
- Używaj display_type do definiowania sekcji i notatek zamiast tworzyć „udawane” linie produktowe — utrzymuje to porządek w raportach i walidacjach.
- Przy integracjach API twórz linie przez order_id lub stosuj poprawne komendy w polu order_line_ids na sale.order — to zapewnia integralność danych.
- Szanuj ograniczenia SQL: linia produktowa powinna mieć product_id i product_uom, natomiast linia sekcyjna musi mieć ustawiony display_type.
- Do niestandardowych cen preferruj reguły cennikowe. Nadpisuj obliczenia tylko wtedy, gdy logika nie jest możliwa do odwzorowania w cennikach.
- Dla własnych pól stosuj prefix x_ lub prefiks modułu, by zmniejszyć ryzyko konfliktów z przyszłymi wersjami Odoo.
Częste błędy
- Tworzenie linii bez order_id. Pole jest wymagane — zawsze twórz pozycje w kontekście zamówienia, by zachować spójność relacji.
- Mieszanie product_id z product_template_id. Dla linii produktowej ustaw product_id; product_template_id służy głównie w przepływach konfiguratora do wyboru wariantu.
- Modyfikowanie price_unit lub discount po częściowym fakturowaniu. Gdy qty_invoiced > 0, zmiany cen mogą wprowadzić niespójności w rozliczeniach.
- Nadpisywanie metod rdzenia bez wywołania super(). To ryzykowne — może złamać integracje i utrudnić upgrade'y.
- Zapominanie o display_type przy liniach sekcji/nota. Brak tego ustawienia spowoduje, że system potraktuje wpis jako linię produktową i może dojść do błędów walidacji.
Podsumowanie
Model sale.order.line to serce modułu sprzedaży w Odoo — przechowuje każdą pozycję ofert i zamówień. Znajomość jego pól i mechanizmów rozszerzania ułatwia konfigurację, personalizację i integrację systemu.
Niezależnie czy jesteś konsultantem mapującym procesy biznesowe, czy deweloperem tworzącym moduły, solidna znajomość sale.order.line pozwoli zaoszczędzić czas i uniknąć typowych pułapek.
Potrzebujesz wsparcia przy wdrożeniu Odoo?
Dasolo wspiera firmy we wdrożeniach, customizacji i optymalizacji Odoo. Specjalizujemy się w integracjach API oraz rozwoju funkcji — mamy praktyczne doświadczenie z architekturą danych i modelami takimi jak sale.order.line.
Jeśli potrzebujesz pomocy przy wdrożeniu Odoo, tworzeniu modułów czy integracjach — chętnie pomożemy. Umów demo by omówić Twój projekt.