Skip to Content

The sale.order.line Model: Understanding Odoo's Sales Order Line Architecture

A complete guide to Odoo's sales order line model for developers and functional consultants
March 10, 2026 by
The sale.order.line Model: Understanding Odoo's Sales Order Line Architecture
Dasolo
| No comments yet

Introduction


In Odoo, models define how data is structured and stored in the database. Every piece of business data you work with, from sales orders to invoices to contacts, lives in a model.


Understanding Odoo models is essential for both developers and functional consultants. Models are the foundation of the Odoo data architecture. They define fields, relationships, and business logic.


This article focuses on one of the most important models in the Sales module: sale.order.line. Whether you are building custom modules, integrating external systems, or configuring pricing workflows, you will work with this model.

What is the sale.order.line Model


The sale.order.line model represents individual line items on a quotation or sales order in Odoo. Each line typically corresponds to one product, with quantity, price, and tax information.


This model in Odoo is used by the Sales module (sale). It inherits from analytic.mixin for project cost tracking and timesheet integration. When you add a product to a quotation, you are creating a sale.order.line record.


The model is defined in the sale module. Other modules extend it through Odoo model inheritance. For example, sale_stock adds delivery-related fields. sale_margin adds margin calculations. Each module adds what it needs without duplicating the core structure.

Key Fields in the Model


Here are the most important Odoo fields in the sale.order.line model. Understanding these will help you work effectively with quotations and sales orders.


1. order_id

Type: Many2one (sale.order). Required. Reference to the parent sales order. This field links each line to its parent. Lines are deleted when the order is deleted (cascade).


2. sequence

Type: Integer. Default 10. Controls the display order of lines on the order. Used for sorting sections, notes, and product lines.


3. company_id

Type: Many2one (res.company). Related from order_id. Used for multi-company rules and access control.


4. currency_id

Type: Many2one (res.currency). Related from order_id. Used for all monetary fields on the line. Ensures correct currency for pricing.


5. order_partner_id

Type: Many2one (res.partner). Related from order_id. The customer. Used for pricelist and tax rules.


6. salesman_id

Type: Many2one (res.users). Related from order_id. The salesperson. Used for commission and reporting.


7. state

Type: Selection. Related from order_id. Order status (draft, sent, sale, done, cancel). Drives which fields are editable.


8. display_type

Type: Selection. Values: line_section or line_note. When set, the line is a section header or a note, not a product line. Product fields are empty.


9. is_downpayment

Type: Boolean. Indicates if the line is a down payment. Down payments are invoiced separately.


10. is_expense

Type: Boolean. True when the line comes from an expense or vendor bill. Used for project cost tracking.


11. product_id

Type: Many2one (product.product). The product being sold. Domain restricts to saleable products. Required for product lines.


12. product_template_id

Type: Many2one (product.template). Computed from product_id. Used by the product configurator for variant selection.


13. name

Type: Text. The line description. Computed from product and custom attributes. Includes variant details when applicable.


14. product_uom_qty

Type: Float. Required. The quantity ordered. Default 1.0. Can be driven by packaging.


15. product_uom

Type: Many2one (uom.uom). Unit of measure. Defaults from product. Used for quantity and pricing.


16. tax_id

Type: Many2many (account.tax). Taxes applied to the line. Computed from product and fiscal position.


17. price_unit

Type: Float. Required. Unit price per product_uom. Computed from pricelist or product. Can be overridden manually.


18. discount

Type: Float. Discount percentage. Applied to price_unit before tax.


19. price_subtotal

Type: Monetary. Subtotal before tax. Computed from quantity, unit price, and discount.


20. price_tax

Type: Float. Total tax amount. Computed from price_subtotal and tax_id.


21. price_total

Type: Monetary. Total including tax. The main amount for invoicing.


22. product_packaging_id

Type: Many2one (product.packaging). Optional packaging (e.g. box of 12). When set, quantity can be driven by packaging.


23. customer_lead

Type: Float. Lead time in days. Days between order confirmation and shipment. Used for delivery date calculation.


24. qty_delivered

Type: Float. Quantity delivered. Updated by stock moves or manually. Used for partial invoicing.


25. qty_invoiced

Type: Float. Quantity already invoiced. Computed from invoice lines.


26. qty_to_invoice

Type: Float. Remaining quantity to invoice. Computed from qty_delivered and qty_invoiced.


27. invoice_status

Type: Selection. Values: upselling, invoiced, to invoice, no. Indicates invoicing state for the line.


28. invoice_lines

Type: Many2many (account.move.line). Links to invoice lines created from this sale line. Used for traceability.


29. create_date

Type: Datetime. When the record was created. Automatically managed by Odoo.


30. write_date

Type: Datetime. When the record was last modified. Used for auditing.

How This Model Is Used in Business Workflows


1. Quotation and Sales Order

When a salesperson creates a quotation, they add products. Each product becomes a sale.order.line. The lines show quantity, price, discount, and total. The order is confirmed when the customer accepts.


2. Pricelist and Discounts

Pricelists are applied per line. The price_unit and discount fields are computed from pricelist rules. Volume discounts or customer-specific pricing are handled here.


3. Delivery and Invoicing

When stock is delivered, qty_delivered is updated. Invoicing can be done per delivery or at once. The invoice_status field guides the user on what remains to invoice.


4. Project and Services

For service products, the lines link to project tasks and timesheets. The analytic.mixin inheritance enables cost tracking per project.


5. E-commerce and Portal

Website visitors add products to cart. Each cart line becomes a sale.order.line when the order is created. The product configurator uses product_template_id and custom attributes.

How Developers Extend This Model


Developers extend sale.order.line using several patterns. Odoo model inheritance is the main mechanism.


Model Inheritance

Use _inherit = 'sale.order.line' to extend the model. Add new fields, override methods, or add constraints. The inherit model in Odoo keeps your changes in a separate module for easy upgrades.


Adding Fields

Define new Odoo fields in your inherited model. Use the right field type: Char, Many2one, Boolean, Integer, Text, Selection. Consider company-dependent fields for multi-company.


Python Extensions

Override _compute_price_unit, _compute_price_subtotal, or create/write to add logic. Use super() to call the original. Be careful with computed fields and their dependencies.


Odoo Studio

Odoo Studio lets you add fields without code. Good for quick customizations. For complex logic or upgrades, custom modules are more maintainable.

Best Practices


  • Use display_type for sections and notes instead of fake product lines. This keeps reporting clean.
  • When building API integrations, create lines via the order_id. Use the order_line_ids field on sale.order with the correct command format.
  • Respect the SQL constraints. A product line must have product_id and product_uom. A section or note must have display_type.
  • For custom pricing, use pricelist rules when possible. Override compute methods only when you need logic not supported by pricelists.
  • For custom fields, use the x_ prefix or a module prefix to avoid conflicts with future Odoo versions.

Common Mistakes


  • Creating lines without order_id. The field is required. Always create lines in the context of an order.
  • Mixing up product_id and product_template_id. For product lines, set product_id. For configurator flows, use product_template_id to select a variant.
  • Modifying price_unit or discount after invoicing. Once qty_invoiced is greater than zero, price changes can cause inconsistencies.
  • Overriding core methods without calling super(). This can break other modules or future upgrades.
  • Forgetting to set display_type for section or note lines. Without it, the line is treated as a product line and will fail validation.

Conclusion


The sale.order.line model is central to Odoo Sales. It stores each product line on quotations and orders. Understanding its fields and how modules extend it will help you configure, customize, and integrate Odoo effectively.


Whether you are a functional consultant mapping business processes or a developer building custom modules, a solid grasp of sale.order.line will save time and prevent errors.

Need Help With Your Odoo Implementation?


Dasolo helps companies implement, customize, and optimize Odoo. We specialize in API integrations and Odoo development. Our team has deep experience with the Odoo data architecture and models like sale.order.line.


If you need help with your Odoo implementation, custom modules, or integrations, we are here to help. Book a demo to discuss your project.

The sale.order.line Model: Understanding Odoo's Sales Order Line Architecture
Dasolo March 10, 2026
Share this post
Sign in to leave a comment