GuideOdoo InventoryMarch 13, 2026

Odoo 19 Lot & Serial Number Tracking:
Full Traceability from Receipt to Customer

INTRODUCTION

Your Inventory Is Only as Good as Your Ability to Trace It

A customer calls about a defective batch of electronic components they received last Tuesday. Your warehouse manager opens the ERP, searches the delivery order, and finds… nothing. No lot number, no serial number, no link back to the supplier shipment that brought those components in. The only way to investigate is to manually cross-reference purchase orders, delivery dates, and supplier invoices—a process that takes hours instead of seconds.

This scenario plays out daily in companies that skip lot and serial number configuration during their Odoo implementation. The inventory module ships with powerful traceability features, but they require deliberate setup. Traceability doesn't happen by default—it happens by design.

This guide covers every layer of lot and serial number tracking in Odoo 19: the difference between lots and serials, how to configure products for tracking, how to assign numbers during receipt and delivery, how to run traceability reports, and how to manage expiry dates and product recalls. We include the actual Python models, XML views, and operational workflows so you can implement full traceability in your warehouse.

01

Lot Tracking vs Serial Number Tracking: When to Use Each

Odoo offers two distinct tracking mechanisms, and choosing the wrong one creates operational headaches that are painful to reverse once you have live inventory. Understanding the difference upfront saves hours of data cleanup later.

CriteriaLot TrackingSerial Number Tracking
UniquenessOne lot number covers multiple units (e.g., 500 units in Lot A2024-03)Each unit gets a globally unique serial number
Quantity per numberAny quantityExactly 1.00
Best forFood, chemicals, pharmaceuticals, raw materials, bulk goodsElectronics, machinery, vehicles, high-value assets, warranty items
Expiry datesSet per lot—all units in the lot share the same expirySet per serial—rarely used since each unit is individual
Recall scopeRecall an entire lot (batch recall)Recall individual units by serial number
Operational overheadLow—scan one barcode per batchHigh—scan every individual unit
Odoo fieldtracking = 'lot'tracking = 'serial'
Decision Framework

Ask yourself: "If this product is defective, do I need to recall every unit individually, or can I recall the entire production batch?" If you need individual unit recall (warranty claims, asset tracking), use serial numbers. If batch-level recall is sufficient (food safety, chemical compliance), use lots. If you don't need recall capability at all, don't enable tracking—it adds scanning overhead to every warehouse operation.

02

Configuring Products for Lot and Serial Number Tracking in Odoo 19

Tracking configuration lives on the product template. Once you set a tracking type and start processing inventory moves, changing the tracking type on a product with existing stock requires careful migration. Get this right during initial setup.

Step 1: Enable Tracking on the Product Form

Navigate to Inventory → Products → Products, open a product, and go to the Inventory tab. Under the Traceability section, set the Tracking field:

Python — Product tracking field definition (stock module)
# In stock/models/product_template.py
class ProductTemplate(models.Model):
    _inherit = "product.template"

    tracking = fields.Selection(
        selection=[
            ("none", "No Tracking"),
            ("lot", "By Lots"),
            ("serial", "By Unique Serial Number"),
        ],
        string="Tracking",
        default="none",
        required=True,
        help="Ensure the traceability of a storable product "
             "in your warehouse.",
    )

Step 2: Enable Lots & Serial Numbers in Settings

Before the tracking field appears on product forms, you must enable the feature globally. Go to Inventory → Configuration → Settings and activate Lots & Serial Numbers under the Traceability section. This activates the stock.lot model and adds the tracking field to the product form:

XML — Settings toggle (simplified)
<record id="stock.action_stock_config_settings"
        model="ir.actions.act_window">
  <field name="res_model">res.config.settings</field>
</record>

<!-- The setting controls group_stock_lot -->
<field name="group_stock_lot"
       string="Lots & Serial Numbers"
       implied_group="stock.group_stock_lot"
       help="Track products using lots or serial numbers"/>

Step 3: Configure Lot/Serial Auto-Generation (Optional)

Odoo 19 can auto-generate lot or serial numbers on receipts. This avoids manual entry and enforces consistent naming conventions. Configure this under Inventory → Configuration → Settings → Traceability:

Python — Auto-generation sequence on stock.picking.type
class StockPickingType(models.Model):
    _inherit = "stock.picking.type"

    use_create_lots = fields.Boolean(
        string="Create New Lots/Serial Numbers",
        default=True,
        help="If checked, new lots/serial numbers can be "
             "created during this operation type.",
    )
    use_existing_lots = fields.Boolean(
        string="Use Existing Lots/Serial Numbers",
        default=True,
        help="If checked, existing lot/serial numbers "
             "can be selected during this operation.",
    )

# Configure auto-generation pattern via sequence:
# Inventory > Configuration > Warehouse Management
#   > Operation Types > Receipts
# Set "Lot/Serial Number" sequence prefix, e.g.:
#   LOT/{{product.default_code}}/%(year)s-
# This generates: LOT/ELEC-001/2026-00001
Naming Convention Tip

Establish a lot/serial naming convention before your first receipt. A good pattern includes the product category, year, and a sequential number: FOOD-2026-00001 for food items, ELEC-SN-2026-00001 for electronics. Once warehouse staff start scanning arbitrary lot names, you'll never get consistency back without a data migration.

03

Assigning Lot and Serial Numbers During Receipt and Delivery

Configuration means nothing if your warehouse team doesn't assign tracking numbers during operations. Odoo enforces this at the stock move level—you cannot validate a picking for a tracked product without assigning lot or serial numbers. Here's the complete workflow.

Lot Assignment on Receipt (Incoming Shipment)

When a purchase order generates a receipt, tracked products require lot/serial assignment before validation:

  1. Open the receipt (Inventory → Operations → Receipts)
  2. Click Detailed Operations (or the serial number icon) on the move line
  3. For lot-tracked products: enter the lot name (or scan the supplier's lot barcode) and the quantity received in that lot
  4. For serial-tracked products: enter each serial number individually, or use Generate Serial Numbers to create a range automatically
  5. Click Validate—Odoo creates the stock.lot records and links them to the stock moves
Python — The stock.lot model (core fields)
class StockLot(models.Model):
    _name = "stock.lot"
    _description = "Lot/Serial"

    name = fields.Char(
        string="Lot/Serial Number",
        required=True, index=True,
    )
    product_id = fields.Many2one(
        "product.product", string="Product",
        required=True, index=True,
    )
    company_id = fields.Many2one(
        "res.company", string="Company",
        required=True, index=True,
    )
    # Traceability link
    quant_ids = fields.One2many(
        "stock.quant", "lot_id",
        string="Quants",
    )

    _sql_constraints = [
        ("unique_lot",
         "unique(name, product_id, company_id)",
         "The lot/serial number must be unique "
         "per product and company!"),
    ]

Serial Number Assignment on Delivery (Outgoing Shipment)

When a sales order generates a delivery, Odoo requires the warehouse operator to specify which lot or serial number is being shipped. This is the critical link that enables end-to-end traceability—from the supplier who sent you the goods to the customer who received them:

Python — Validation check (simplified from stock.move)
# stock/models/stock_move.py (simplified)
class StockMove(models.Model):
    _inherit = "stock.move"

    def _action_done(self):
        for move in self:
            if move.has_tracking != "none":
                for ml in move.move_line_ids:
                    if not ml.lot_id and not ml.lot_name:
                        raise UserError(_(
                            "You need to supply a Lot/Serial "
                            "Number for product: %s",
                            move.product_id.display_name,
                        ))
                    if (move.has_tracking == "serial"
                            and ml.quantity > 1):
                        raise UserError(_(
                            "A serial number can only be "
                            "linked to a single unit of %s. "
                            "Quantity: %s",
                            move.product_id.display_name,
                            ml.quantity,
                        ))
        return super()._action_done()
Barcode Scanner Integration

For high-volume warehouses, manual lot/serial entry is a non-starter. Use Odoo's Barcode app to scan lot numbers directly during receipt and delivery operations. The barcode app auto-populates the lot field on the move line when a lot barcode is scanned, eliminating typos and reducing processing time per line from ~15 seconds to ~2 seconds.

04

Traceability Reports: Tracking a Product from Supplier to Customer

The payoff of all this tracking setup is the traceability report—a single view that shows every inventory movement linked to a specific lot or serial number. This is the report your quality team uses during audits, your customer support team uses during complaints, and your compliance team uses during recalls.

Accessing the Traceability Report

Navigate to Inventory → Reporting → Traceability. You can also access it directly from a lot record by clicking the Traceability smart button. The report shows the complete chain:

ColumnWhat It ShowsWhy It Matters
ReferenceThe stock picking reference (WH/IN/00042, WH/OUT/00108)Links to the actual receipt or delivery document
ProductProduct name and internal referenceConfirms the right product is being traced
Lot/SerialThe lot or serial numberThe primary search key for traceability
DateTimestamp of the stock movementEstablishes the chronological chain of custody
FromSource location (Vendor, WH/Stock, etc.)Shows where the product came from
ToDestination location (WH/Stock, Customer, etc.)Shows where the product went
QuantityUnits moved in this operationTracks how many units from this lot/serial were involved

Upstream & Downstream Tracing

Odoo 19's traceability report supports two critical tracing directions:

  • Upstream (backward) tracing: Given a lot/serial shipped to a customer, trace back to the supplier who provided it. Essential for: "Customer reported defect—which supplier batch did this come from?"
  • Downstream (forward) tracing: Given a supplier lot, trace forward to every customer who received units from it. Essential for: "Supplier issued recall on batch X—which customers are affected?"
Python — Programmatic traceability query
# Find all customers who received a specific lot
lot = self.env["stock.lot"].search([
    ("name", "=", "LOT-2026-00042"),
    ("product_id.default_code", "=", "ELEC-001"),
], limit=1)

# Get all outgoing moves for this lot
outgoing_moves = self.env["stock.move.line"].search([
    ("lot_id", "=", lot.id),
    ("picking_id.picking_type_code", "=", "outgoing"),
    ("state", "=", "done"),
])

# Extract affected customers
affected_customers = outgoing_moves.mapped(
    "picking_id.partner_id"
)
for partner in affected_customers:
    print(f"Customer: {partner.name}, "
          f"Delivery: {partner.picking_ids.mapped('name')}")
Audit Trail Integrity

The traceability report is only as reliable as the data entered during operations. If warehouse staff bypass lot assignment by using force validation or if they assign placeholder lot numbers like "TBD" or "123", your traceability chain is broken. Disable the "No Validation" setting on picking types for tracked products and train your team to treat lot/serial assignment as a mandatory step, not an optional one.

05

Expiry Date Tracking and Product Recall Management

For industries dealing with perishable goods—food, pharmaceuticals, cosmetics, chemicals—lot tracking without expiry dates is incomplete. Odoo 19's Expiration Dates feature extends the stock.lot model with date fields that integrate into inventory valuation, FEFO picking strategies, and automated alerts.

Enabling Expiry Date Tracking

Activate Expiration Dates under Inventory → Configuration → Settings → Traceability. This adds four date fields to every lot:

Python — Expiry fields on stock.lot (product_expiry module)
class StockLot(models.Model):
    _inherit = "stock.lot"

    use_date = fields.Datetime(
        string="Best Before Date",
        help="Date after which the product may begin to "
             "deteriorate, without necessarily being dangerous.",
    )
    expiration_date = fields.Datetime(
        string="Expiration Date",
        help="Date after which the product becomes dangerous "
             "and must not be consumed or sold.",
    )
    removal_date = fields.Datetime(
        string="Removal Date",
        help="Date after which the product should be removed "
             "from stock (before expiration).",
    )
    alert_date = fields.Datetime(
        string="Alert Date",
        help="Date on which an alert should be raised about "
             "the lot approaching expiry.",
    )

FEFO Removal Strategy (First Expiry, First Out)

With expiry dates on lots, you can configure locations or product categories to use FEFO (First Expiry, First Out) as the removal strategy. This ensures the warehouse picks the lot closest to expiry first, reducing waste:

XML — Setting FEFO on a stock location
<record id="stock_location_fefo_example"
        model="stock.location">
  <field name="name">Cold Storage</field>
  <field name="usage">internal</field>
  <field name="removal_strategy_id"
         ref="product_expiry.removal_fefo"/>
</record>

<!-- Available removal strategies:
     - FIFO (First In, First Out) - default
     - LIFO (Last In, First Out)
     - FEFO (First Expiry, First Out)
     - Closest location -->

Managing Product Recalls

When a recall is necessary, the workflow combines traceability reports with expiry tracking:

  1. Identify the affected lot(s) using the supplier's recall notice or your quality inspection records
  2. Run a downstream traceability report to find every customer who received units from the affected lot
  3. Check current stock—search stock.quant to find units from the recalled lot still in your warehouse
  4. Create a scrap order or internal transfer to quarantine recalled stock
  5. Notify affected customers using the partner list from step 2
Python — Quarantine recalled lot stock
# Find all quants for the recalled lot
recalled_lot = self.env["stock.lot"].search([
    ("name", "=", "FOOD-2026-00089"),
], limit=1)

quants = self.env["stock.quant"].search([
    ("lot_id", "=", recalled_lot.id),
    ("location_id.usage", "=", "internal"),
    ("quantity", ">", 0),
])

# Create scrap orders for each quant
for quant in quants:
    self.env["stock.scrap"].create({
        "product_id": quant.product_id.id,
        "lot_id": quant.lot_id.id,
        "scrap_qty": quant.quantity,
        "location_id": quant.location_id.id,
        "origin": "RECALL: FOOD-2026-00089",
    })
Automated Expiry Alerts

Configure a scheduled action (ir.cron) to check the alert_date field daily and send email notifications to the quality team. Odoo's product_expiry module includes a basic cron for this, but most companies need to customize the notification logic—adding Slack alerts, filtering by product category, or escalating to management when high-value lots approach expiry.

06

3 Lot & Serial Number Tracking Mistakes That Break Traceability in Production

1

Changing the Tracking Type on a Product with Existing Stock

You decide to switch a product from lot tracking to serial tracking (or from "no tracking" to "lot") after you already have inventory in the system. Odoo lets you change the tracking field on the product form, but existing quants don't retroactively get lot/serial numbers. Your on-hand stock shows up as untracked, the traceability report has gaps, and warehouse operations for that product start throwing validation errors because old quants have no lot assigned.

Our Fix

Never change tracking type on products with existing stock in a live environment. Instead: (1) create an inventory adjustment to zero out the untracked stock, (2) change the tracking type, (3) create a new inventory adjustment to add the stock back with proper lot/serial numbers. This preserves the audit trail and ensures every quant has a valid tracking reference going forward.

2

Allowing Duplicate Lot Names Across Different Products

A supplier ships two different products—resistors and capacitors—both labeled with the same lot number "2026-B42." Your warehouse team creates lot "2026-B42" for the resistors and tries to create the same lot name for the capacitors. In Odoo, the stock.lot uniqueness constraint is per product per company, so this works. But when your quality team searches for lot "2026-B42" in the traceability report, they get mixed results from two different products, creating confusion during recall investigations.

Our Fix

Prefix lot numbers with the product's internal reference: RES-001-2026-B42 and CAP-005-2026-B42. Configure the lot sequence on the receiving operation type to include %(product.default_code)s as a prefix. This makes every lot name globally unique in practice, even though the database constraint only requires per-product uniqueness.

3

Not Tracking Lots Through Manufacturing (Only Receipts and Deliveries)

You set up lot tracking for incoming raw materials and outgoing finished goods, but your manufacturing orders don't consume specific lots. The bill of materials uses generic components without lot assignment. When a customer reports a defect in finished product lot "FG-2026-00150," you can trace it to the delivery and back to the manufacturing order—but you cannot determine which raw material lots were used in that production run. Your traceability chain has a gap right in the middle.

Our Fix

Enable "Track Components" on your manufacturing operation type and configure work order steps to scan raw material lot numbers during consumption. In the manufacturing order, use Detailed Operations on each component move to assign the specific lot being consumed. This creates a complete traceability link: supplier lot → raw material lot consumed in MO → finished good lot → customer delivery. The cost is additional scanning time per work order, but the traceability value is essential for industries with regulatory requirements (FDA, ISO 22000, IATF 16949).

BUSINESS ROI

What Full Traceability Saves Your Business

Lot and serial number tracking isn't a warehouse project—it's a risk management investment:

90%Faster Recall Response

With downstream traceability, identifying affected customers takes minutes instead of days. A targeted recall costs a fraction of a blanket recall that pulls all stock.

40%Less Expired Stock Waste

FEFO removal strategies and automated expiry alerts ensure the oldest stock ships first. Companies report 30-40% reduction in write-offs within the first year of implementation.

100%Audit Compliance

FDA, ISO, and GMP auditors require end-to-end traceability. Without it, you fail the audit. With Odoo's traceability reports, you pass it with a single search.

For a food distributor handling 2,000 SKUs with a 3% annual spoilage rate on $5M inventory, reducing spoilage by 40% through FEFO and expiry alerts saves $60,000 per year. Add the avoided cost of a single blanket recall (typically $250K-$500K for a mid-size distributor), and the ROI of proper traceability setup is measured in multiples, not percentages.

SEO NOTES

Optimization Metadata

Meta Desc

Complete guide to Odoo 19 lot and serial number tracking. Configure products, assign lots on receipt, run traceability reports, manage expiry dates, and handle recalls.

H2 Keywords

1. "Lot Tracking vs Serial Number Tracking: When to Use Each"
2. "Configuring Products for Lot and Serial Number Tracking in Odoo 19"
3. "Traceability Reports: Tracking a Product from Supplier to Customer"
4. "Expiry Date Tracking and Product Recall Management"
5. "3 Lot & Serial Number Tracking Mistakes That Break Traceability in Production"

Traceability Is Not Optional—It's the Foundation of Inventory Trust

Every product that enters your warehouse without a lot number is a product you can't trace when something goes wrong. Every serial number you skip during delivery is a warranty claim you can't verify. Every expiry date you don't track is spoiled stock you'll discover too late. The cost of setting up traceability is measured in hours of configuration; the cost of not having it is measured in failed audits, blanket recalls, and customer trust you can't rebuild.

If your Odoo warehouse isn't tracking lots and serial numbers yet, now is the time. We implement full traceability systems—from product configuration and barcode scanning to expiry management and recall workflows. The setup typically takes 3-5 days depending on your product catalog, and the first audit it passes will justify the investment.

Book a Free Traceability Audit