Skip to content

Stock Lot Documentation

Overview

The Stock Lot module (stock.lot) manages lot numbers, serial numbers, and batch tracking for inventory items. It enables traceability, expiry management, quality control, and detailed tracking of individual units or batches throughout the supply chain.


Model Information

Model Name: stock.lot
Display Name: Lot / Serial Number
Key Fields: number

Features

  • ✅ Audit logging enabled
  • ❌ Multi-company support (not enforced)
  • ❌ Auto-sync disabled
  • ✅ Unique key constraint on number

Lot Tracking Types

Type Code Description
Product product Standard product batches (default)
Asset asset Fixed asset tracking
Sample sample Laboratory samples

Lot States

State Description
active Lot is active and available for use
inactive Lot is deactivated (excluded from balance calculations)

Key Fields Reference

Header Fields

Field Type Required Description
number Char Unique lot/serial number
lot_tracking_type Selection Product/Asset/Sample (default: product)
product_id Many2One Associated product
state Selection active/inactive
description Text Lot description

Date Fields

Field Type Description
received_date DateTime When lot was received
mfg_date Date Manufacturing date
expiry_date Date Expiration date
life_75_date Date 75% shelf life date (computed)
life_50_date Date 50% shelf life date (computed)
life_remain_percent Decimal Remaining shelf life % (computed)

Physical Properties

Field Type Description
weight Decimal Weight (kg)
net_weight Decimal Net weight (kg)
gross_weight Decimal Gross weight (kg)
width Decimal Width dimension
length Decimal Length dimension
thickness Decimal Thickness dimension
diameter Decimal Diameter dimension
area_m2 Decimal Area in square meters
temperature Decimal Storage temperature

Tracking Fields

Field Type Description
supp_lot_no Char Supplier's lot number
po_number Many2One Purchase order reference
project_id Many2One Associated project
url Char External URL/link
ratio Char Conversion ratio

Quality Control Fields

Field Type Description
defect_categ Many2One Defect category
grade Text Quality grade
test_description Char Test description
notes_and_comments Char Additional notes

Equipment/Asset Fields (for asset tracking)

Field Type Description
asset_id Many2One Fixed asset reference
machine_number Many2One Machine number
last_calibration_date Date Last calibration
next_calibration_date Date Next calibration due
last_maintenance Date Last maintenance
next_maintenance Date Next maintenance due
equipment_status Selection active/under_maintenance/out_of_service

Relationship Fields

Field Type Description
comments One2Many Discussion thread
stock_balances One2Many Current stock quantities by location
moves One2Many All stock transactions
expiry_moves One2Many Expiry-related movements
lot_items One2Many Sub-items in lot
lot_lines One2Many Lot line details
validate_lines One2Many Validation records

Computed Fields

Field Type Description
last_location_id Many2One Last known location
lot_items_summary Char Summary of lot items
total_weight Decimal Total weight from lot lines
total_pcs Decimal Total pieces from lot lines

API Methods

1. Create Lot

Method: create(vals, context)

Creates a new lot number.

Context Options:

context = {
    "sequence_name": "LOT-BATCH"  # Specific sequence to use
}

Example:

# Auto-generated lot number
lot_id = get_model("stock.lot").create({
    "product_id": 100,
    "mfg_date": "2025-10-01",
    "expiry_date": "2026-10-01",
    "weight": 50.5,
    "description": "Batch A from supplier XYZ"
}, context={"sequence_name": "stock_lot"})

# Manual lot number
manual_lot = get_model("stock.lot").create({
    "number": "LOT-2025-001",
    "product_id": 100,
    "lot_tracking_type": "product"
})


2. Update Expired Lots

Method: update_expired_lots(context)

Automatically processes expired lots and moves them to expiry location.

Behavior: - Runs as scheduled task - Finds lots past expiry_date - Creates stock movements to expiry location - Uses settings.lot_expiry_journal_id

Example:

# Typically called by cron job
get_model("stock.lot").update_expired_lots()


3. Get Life Dates

Method: get_life_dates(ids, context)

Calculates 75% and 50% shelf life milestone dates.

Returns:

{
    lot_id: {
        "life_75_date": "2026-03-15",  # 25% consumed
        "life_50_date": "2026-06-15"   # 50% consumed
    }
}

Example:

# Automatically computed when mfg_date and expiry_date set
lot = get_model("stock.lot").browse(lot_id)
print(f"75% life at: {lot.life_75_date}")
print(f"50% life at: {lot.life_50_date}")


4. Get Life Remain Percent

Method: get_life_remain(ids, context)

Calculates remaining shelf life percentage.

Returns: Decimal percentage of shelf life remaining

Example:

lot = get_model("stock.lot").browse(lot_id)
if lot.life_remain_percent < 25:
    print(f"Warning: Only {lot.life_remain_percent}% shelf life remaining")


Computed Fields Functions

get_life_dates(ids, context)

Calculates 75% and 50% shelf life milestone dates based on mfg_date and expiry_date

get_life_remain(ids, context)

Returns percentage of shelf life remaining from current date to expiry

get_last_location(ids, context)

Finds most recent location from stock movements

get_lot_items_summary(ids, context)

Generates summary text of lot items

update_total_mt(ids, context)

Sums total weight from lot lines

update_total_pcs(ids, context)

Sums total pieces from lot lines


Common Use Cases

Use Case 1: Create Lot with Expiry Tracking

# Create lot for perishable product
lot_id = get_model("stock.lot").create({
    "product_id": food_product_id,
    "mfg_date": "2025-10-01",
    "expiry_date": "2025-12-31",
    "supp_lot_no": "SUPP-LOT-12345",
    "weight": 100.0,
    "description": "Fresh batch from Farm ABC"
}, context={"sequence_name": "food_lot"})

# Check computed dates
lot = get_model("stock.lot").browse(lot_id)
print(f"Alert at 75% life: {lot.life_75_date}")
print(f"Alert at 50% life: {lot.life_50_date}")

Use Case 2: Serial Number Tracking

# Create individual serial numbers for electronics
for serial in ["SN001", "SN002", "SN003"]:
    get_model("stock.lot").create({
        "number": serial,
        "product_id": laptop_product_id,
        "lot_tracking_type": "asset",
        "asset_id": asset_id,
        "description": f"Laptop serial {serial}"
    })

Use Case 3: Equipment Calibration Tracking

# Track calibration for measurement equipment
equipment_lot = get_model("stock.lot").create({
    "number": "EQUIP-CAL-001",
    "product_id": equipment_id,
    "lot_tracking_type": "asset",
    "last_calibration_date": "2025-10-01",
    "next_calibration_date": "2026-10-01",
    "equipment_status": "active",
    "machine_number_id": machine_id
})

# Check calibration status
lot = get_model("stock.lot").browse(equipment_lot)
if lot.next_calibration_date < date.today():
    print("Calibration overdue!")

Use Case 4: FIFO/FEFO Lot Selection

# Find oldest lots (FIFO - First In First Out)
oldest_lots = get_model("stock.lot").search(
    [["product_id", "=", product_id],
     ["state", "=", "active"]],
    order="received_date"
)

# Find lots expiring soonest (FEFO - First Expired First Out)
expiring_lots = get_model("stock.lot").search(
    [["product_id", "=", product_id],
     ["expiry_date", "!=", None],
     ["state", "=", "active"]],
    order="expiry_date"
)

Best Practices

1. Always Set Expiry for Perishable Goods

# Good: Set expiry dates
lot_vals = {
    "product_id": product_id,
    "mfg_date": mfg_date,
    "expiry_date": expiry_date  # System calculates life dates
}

# System automatically computes:
# - life_75_date
# - life_50_date  
# - life_remain_percent

2. Use Lot States for Control

# Deactivate expired or problematic lots
get_model("stock.lot").write([lot_id], {
    "state": "inactive"  # Excluded from balance calculations
})

# Reactivate if resolved
get_model("stock.lot").write([lot_id], {
    "state": "active"
})
# Always link to PO for traceability
lot_vals = {
    "number": "LOT-2025-001",
    "product_id": product_id,
    "po_number_id": purchase_order_id,  # Traceability
    "supp_lot_no": supplier_lot_number,  # Supplier reference
    "received_date": datetime.now()
}

Database Constraints

Unique Constraint

_key = ["number"]

Each lot number must be globally unique across the system.


Model Relationship Description
stock.balance One2Many Stock quantities per location for this lot
stock.move One2Many All movements of this lot
product Many2One Product this lot belongs to
account.fixed.asset Many2One Fixed asset (for asset tracking)
stock.lot.item One2Many Sub-items within lot
stock.lot.line One2Many Lot line details
pick.validate.line One2Many Validation records

Troubleshooting

"Lot number must be unique"

Cause: Duplicate lot number
Solution: Use unique numbers or let system auto-generate

"Expired lots not moving automatically"

Cause: Expiry journal not configured
Solution: Configure settings.lot_expiry_journal_id

"Lot excluded from balance"

Cause: Lot state is 'inactive'
Solution: Check lot state and reactivate if appropriate

"Missing shelf life dates"

Cause: mfg_date or expiry_date not set
Solution: Set both dates for automatic calculation


Configuration Settings

Required Settings

Setting Location Description
Lot Sequence Sequences For auto-generating lot numbers
Expiry Journal Settings For automatic expiry movements

This documentation is generated for developer onboarding and reference purposes.