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 inventory movements, 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 Odoo: stock.move. Whether you are building custom warehouse modules, integrating external systems, or configuring inventory workflows, you will work with this model.
What is the stock.move Model
The stock.move model represents a single inventory movement in Odoo. It defines the transfer of a product from one location to another. Every time goods leave a shelf, move between warehouses, or get delivered to a customer, a stock.move record is created.
This model in Odoo is used by the Inventory (Stock) module. Sales, Purchase, Manufacturing, and e-commerce all create stock.move records when they trigger inventory operations. When you confirm a delivery order, receive goods from a vendor, or complete a manufacturing order, you are creating or updating stock.move records.
The model is defined in the stock module. Other modules extend it through Odoo model inheritance. Sale adds sale_line_id. Purchase adds purchase_line_id. Manufacturing adds production_id. 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 stock.move model. Understanding these will help you work effectively with inventory movements.
1. name
Type: Char. This field stores the name or description of the move. It is typically built from the product name and quantity. Displayed in many Odoo views and is the primary identifier for the move in lists.
2. product_id
Type: Many2one (product.product). The product being moved. This is a required field. Every stock move must reference a product. Odoo uses this to track quantities and apply inventory rules.
3. product_uom
Type: Many2one (uom.uom). The unit of measure for the quantity. Required. Typically matches the product's default UoM. Odoo validates that quantities are expressed in this unit.
4. product_uom_qty
Type: Float. The quantity to move in the product's unit of measure. This is the demand quantity. When the move is done, quantity_done is the actual quantity processed.
5. quantity
Type: Float. A computed or display field that shows the quantity. Often used in views for user-friendly display. May be the same as product_uom_qty or a converted value.
6. location_id
Type: Many2one (stock.location). The source location. Where the product comes from. Required. For outgoing moves, this is the stock location. For incoming moves, it might be a supplier or production location.
7. location_dest_id
Type: Many2one (stock.location). The destination location. Where the product goes. Required. For incoming moves, this is the stock location. For outgoing moves, it might be a customer or scrap location.
8. picking_id
Type: Many2one (stock.picking). The transfer or picking document that groups this move. A delivery order, receipt, or internal transfer. Moves are grouped by picking for user operations.
9. picking_type_id
Type: Many2one (stock.picking.type). The operation type. Defines whether this is an outgoing delivery, incoming receipt, or internal transfer. Drives workflow and default locations.
10. state
Type: Selection. The current status of the move. Values: draft, waiting, confirmed, assigned, done, cancelled. Draft is not yet confirmed. Assigned means stock is reserved. Done means the move is complete.
11. date
Type: Datetime. The scheduled date for the move. Used for planning and scheduling. Odoo uses this to prioritize transfers and plan operations.
12. date_deadline
Type: Datetime. The deadline for the move. For customer deliveries, this is often the promised delivery date. Used in urgency calculations.
13. origin
Type: Char. Reference to the originating document. For example, a SO number, PO number, or MO number. Helps trace the move back to its source.
14. move_dest_id
Type: Many2one (stock.move). The destination move in a chain. When one move feeds another (e.g. manufacturing output feeds a delivery), this links them. Used for move chaining and propagation.
15. move_orig_ids
Type: One2many (stock.move). The originating moves. The inverse of move_dest_id. Lists moves that feed into this one. Used for traceability.
16. move_line_ids
Type: One2many (stock.move.line). The move lines. Detailed breakdown of the move with lot, serial, or location details. When you reserve or process stock, move lines are created.
17. partner_id
Type: Many2one (res.partner). The partner associated with the move. For customer deliveries, the customer. For vendor receipts, the supplier. Used for address and reporting.
18. company_id
Type: Many2one (res.company). In multi-company setups, this indicates which Odoo company the move belongs to. Affects record visibility and inter-company rules.
19. quantity_done
Type: Float. The quantity that has been processed or done. When the user picks or receives, this is updated. The move is done when quantity_done equals product_uom_qty.
20. reserved_availability
Type: Float. The quantity that has been reserved for this move. Stock is reserved when the move is assigned. This field shows how much is available.
21. create_date
Type: Datetime. Stores the date and time when the record was created. Automatically managed by Odoo. Useful for reporting and auditing.
22. write_date
Type: Datetime. Stores the date and time of the last modification. Also automatically managed. Helps track when data was last updated.
23. sequence
Type: Integer. Display order within a picking. Used to sort moves in the user interface. Lower numbers appear first.
24. priority
Type: Selection. Urgency level. Often 0 for normal, 1 for urgent. Used in scheduling and planning. Urgent moves can be prioritized in operations.
25. description_picking
Type: Char. A description or note for the move. Displayed on picking documents. Useful for special instructions or handling notes.
26. reference
Type: Char. Internal reference or code. Can be used for external system mapping or custom tracking.
27. group_id
Type: Many2one (procurement.group). The procurement group. Groups related moves from the same procurement (e.g. a single sale order). Used for planning and chaining.
28. procure_method
Type: Selection. Make to stock or make to order. Determines whether stock is taken from existing inventory or triggered for production/procurement.
29. sale_line_id
Type: Many2one (sale.order.line). Added by the Sale module. Links the move to the sale order line that triggered it. Used for traceability and reporting.
30. purchase_line_id
Type: Many2one (purchase.order.line). Added by the Purchase module. Links the move to the purchase order line. Used when receiving goods from vendors.
31. production_id
Type: Many2one (mrp.production). Added by Manufacturing. Links the move to the manufacturing order. Used for raw material consumption and finished product output.
32. active
Type: Boolean. Soft delete flag. When False, the record is archived and hidden from default views. Records are not physically deleted.
How This Model Is Used in Business Workflows
1. Customer Delivery
When a sales order is confirmed, Odoo creates stock.move records for each product line. Each move has location_id as the stock location and location_dest_id as the customer location. The moves are grouped in a picking (delivery order). When the warehouse picks and ships, quantity_done is updated and the move state becomes done.
2. Vendor Receipt
When a purchase order is confirmed, Odoo creates stock.move records for incoming goods. location_id is the supplier location, location_dest_id is the stock location. The moves are grouped in a receipt. When goods arrive, the user validates and quantity_done is set.
3. Internal Transfer
Transfers between warehouses or locations create stock.move records. location_id is the source warehouse, location_dest_id is the destination. Used for replenishment, stock rebalancing, or multi-warehouse operations.
4. Manufacturing
Manufacturing orders create two types of moves: incoming raw materials (from stock to production) and outgoing finished products (from production to stock). The production_id field links these moves to the manufacturing order. Move chaining via move_dest_id connects production output to downstream deliveries.
5. Returns and Scrap
Customer returns create reverse moves. Scrap operations create moves to a scrap location. The same stock.move model handles all these flows. The picking_type_id determines the operation type and workflow.
How Developers Extend This Model
Developers extend stock.move using several patterns. Odoo model inheritance is the main mechanism.
Model Inheritance
Use _inherit = 'stock.move' 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. For stock moves, common extensions include custom tracking numbers, carrier references, or batch attributes.
Python Extensions
Override _action_done, _action_assign, or _action_cancel to add logic. Use super() to call the original. Be careful with inventory updates and move chaining. The API model in Odoo exposes these methods for extension.
Odoo Studio
Odoo Studio lets you add fields without code. Good for quick customizations like custom fields on move forms. For complex logic or workflow changes, custom modules are more maintainable.
Best Practices
- Always set location_id and location_dest_id correctly. Wrong locations can cause wrong inventory levels.
- Use the picking_id to group related moves. Do not create moves without a picking when they belong to a transfer.
- When building API integrations, use the XML-RPC or JSON-RPC API. The stock.move model is fully exposed. Map external IDs carefully.
- For custom fields, use the
x_prefix or a module prefix to avoid conflicts with future Odoo versions. - Use move_dest_id and move_orig_ids for traceability. When creating chained moves programmatically, set these links correctly.
- Consider quantity_done vs product_uom_qty when validating. Partial deliveries are allowed.
Common Mistakes
- Creating moves with wrong location types. Source and destination must be compatible (e.g. not both customer locations).
- Modifying product_uom_qty after move lines exist. This can cause inventory inconsistencies. Cancel and recreate if needed.
- Forgetting to set origin. Without origin, tracing a move back to its source document is difficult.
- Overriding _action_done without calling super(). This can break inventory updates and other modules.
- Creating moves directly without going through the proper workflow (e.g. stock.picking). Bypassing the picking can break reservation and assignment.
- Ignoring move_dest_id when splitting or merging moves. Chained moves can get orphaned.
Conclusion
The stock.move model is central to Odoo inventory. It stores every movement of goods from one location to another. Understanding its fields and how modules extend it will help you configure, customize, and integrate Odoo effectively.
Whether you are a functional consultant mapping warehouse processes or a developer building custom modules, a solid grasp of stock.move 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 stock.move.
If you need help with your Odoo implementation, custom modules, or integrations, we are here to help. Book a demo to discuss your project.