Skip to content

Pick Validate Line Documentation

Overview

The Pick Validate Line module (pick.validate.line) represents individual items being validated during the picking validation process. Each line contains product details, validated quantities, lot/serial tracking, container information, and supports automatic lot creation and container content expansion.


Model Information

Model Name: pick.validate.line
Display Name: Item Validation
Key Fields: N/A

Features

  • ✅ Automatic lot creation support
  • ✅ Container content expansion
  • ✅ Net weight calculation
  • ✅ Unique lot validation
  • ❌ Permanent storage (transient parent)

Key Fields Reference

Line Fields

Field Type Required Description
validate_id Many2One Parent validation record (pick.validate)
move_id Many2One Associated stock movement (stock.move)
product_id Many2One Product being validated (product), readonly
lot_id Many2One Lot/Serial number (stock.lot)
container_id Many2One Container reference (stock.container)
lot Char Manual lot/serial entry (deprecated)
qty Decimal Validated quantity (scale: 6)
uom_id Many2One Unit of measure (uom)
qty2 Decimal Gross weight (scale: 6)
container_to_id Many2One Destination container (stock.container)
pick_id Many2One Stock picking reference (stock.picking)
lot_no Char Lot/Serial number text
container_no Char Container number text
packaging_id Many2One Packaging type (stock.packaging)
container_type_id Many2One Container type (stock.container.type)

Computed Fields

Field Description
net_weight Calculated net weight (qty2 - packaging weight - container weight)

API Methods

1. Default Get

Method: default_get(field_names, context)

Pre-populates line data from stock move.

Context Options:

context = {
    "move_id": 123,                       # Stock move to load
}

Behavior: - Loads product, lot, quantity, UoM from stock move - Pre-fills all relevant fields for validation

Example:

# Load line from stock move
line_data = get_model("pick.validate.line").default_get(
    field_names=None,
    context={"move_id": 456}
)

# Result contains pre-populated data
print(line_data["product_id"])  # [product_id, "Product Name"]
print(line_data["qty"])          # Original quantity


2. Create Validation Line

Method: create(vals, context)

Creates or updates a validation line with automatic lot and container handling.

Context Options:

context = {
    "create_lot": True,                   # Auto-create lot if not found
    "lot_no": "LOT-2025-001",            # Lot number to find/create
    "container_no": "CONT-001",           # Container to find/create
    "product_id": 123,                    # Product reference
}

Behavior: - Creates new lots if create_lot=True or lot_no provided - Prevents new lot creation if product has prevent_new_lot=True - Auto-creates containers if specified - Sets default packaging and container type from product - Validates unique lots if required

Example:

# Create validation line with new lot
line_id = get_model("pick.validate.line").create({
    "product_id": 456,
    "qty": 10,
    "uom_id": 1,
    "pick_id": picking_id,
    "move_id": move_id
}, context={
    "create_lot": True,
    "lot_no": "LOT-2025-NEW",
    "container_no": "CONT-A-001"
})


3. Add Line with Container Contents

Method: add_line(vals, context)

Adds validation lines, expanding container contents if applicable.

Parameters: - vals (dict): Line values - context["container_no"]: Container number to expand

Behavior: - If container exists and has contents, creates multiple lines for each item - If no container contents, creates single line - Validates product matches container contents

Returns: Dictionary with pick_validate_line_id and product_id

Example:

# Add line that expands container contents
result = get_model("pick.validate.line").add_line({
    "pick_id": 123,
    "move_id": 456,
    "product_id": 789,
    "qty": 1,
    "uom_id": 1
}, context={"container_no": "CONT-MULTI"})

# Returns:
{
    "pick_validate_line_id": 999,
    "product_id": 789
}

# If container has 3 items, 3 lines are created automatically


4. Validate Line

Method: validate(ids, context)

Validates the line (currently prints debug info).

Example:

get_model("pick.validate.line").validate([line_id])


Computed Fields Functions

get_net_weight(ids, context)

Calculates net weight by subtracting packaging and container weights from gross weight.

Formula:

net_weight = qty2 - (packaging_weight * qty) - container_weight

Example:

# Line with gross weight
line = get_model("pick.validate.line").browse(line_id)

# Computed automatically
print(f"Gross: {line.qty2} kg")
print(f"Net: {line.net_weight} kg")
# Net = Gross - (packaging * qty) - container


Model Relationship Description
pick.validate Many2One Parent validation wizard
stock.move Many2One Associated stock movement
product Many2One Product being validated
stock.lot Many2One Lot/serial tracking
stock.container Many2One Container reference
stock.packaging Many2One Packaging information
stock.container.type Many2One Container type
stock.picking Many2One Picking reference
uom Many2One Unit of measure

Common Use Cases

Use Case 1: Validate with New Lot Creation

# Validate item and create new lot number
line_id = get_model("pick.validate.line").create({
    "pick_id": picking_id,
    "move_id": move_id,
    "product_id": product_id,
    "qty": 50,
    "uom_id": uom_id
}, context={
    "create_lot": True,
    "lot_no": "LOT-2025-OCT-001"
})

# New lot created and linked automatically
line = get_model("pick.validate.line").browse(line_id)
print(f"Lot created: {line.lot_id.number}")

Use Case 2: Validate with Container Expansion

# Container "BOX-001" contains:
# - Product A: 10 units
# - Product B: 5 units
# - Product C: 8 units

# Add line for the container
result = get_model("pick.validate.line").add_line({
    "pick_id": picking_id,
    "move_id": move_id,
    "product_id": None,  # Will be determined from container
    "qty": 1,
    "uom_id": unit_id
}, context={"container_no": "BOX-001"})

# Result: 3 lines created automatically, one for each product
# Each line has correct product_id, qty, lot_id from container contents

Use Case 3: Validate with Weight Calculation

# Validate item with gross weight
line_id = get_model("pick.validate.line").create({
    "pick_id": picking_id,
    "move_id": move_id,
    "product_id": product_id,
    "qty": 10,
    "uom_id": uom_id,
    "qty2": 52.5,  # Gross weight in kg
    "packaging_id": box_packaging_id,     # Box weighs 2kg
    "container_type_id": pallet_type_id   # Pallet weighs 20kg
})

# Net weight calculated automatically
line = get_model("pick.validate.line").browse(line_id)
print(f"Gross: {line.qty2} kg")          # 52.5 kg
print(f"Net: {line.net_weight} kg")      # 52.5 - (2*10) - 20 = 12.5 kg

Use Case 4: Validate with Existing Lot

# Find existing lot
lot_id = get_model("stock.lot").search([
    ["number", "=", "LOT-2025-001"]
])[0]

# Validate using existing lot
line_id = get_model("pick.validate.line").create({
    "pick_id": picking_id,
    "move_id": move_id,
    "product_id": product_id,
    "qty": 25,
    "uom_id": uom_id,
    "lot_id": lot_id  # Use existing lot
})

Best Practices

1. Always Use Context for Lot Creation

# Good: Use context for lot management
line_id = get_model("pick.validate.line").create({
    "product_id": product_id,
    "qty": 10,
    "uom_id": uom_id
}, context={
    "lot_no": scanned_lot_number,  # ✅ Finds or creates lot
    "create_lot": True
})

# Bad: Manual lot creation
lot_id = get_model("stock.lot").create({"number": lot_no})
line_id = get_model("pick.validate.line").create({
    "product_id": product_id,
    "qty": 10,
    "uom_id": uom_id,
    "lot_id": lot_id  # ❌ More code, less automated
})

2. Check Product Lot Requirements

# Good: Check before creating lots
prod = get_model("product").browse(product_id)

if prod.prevent_new_lot:
    # Only use existing lots
    lot_id = select_existing_lot(product_id)
    context = {}
else:
    # Can create new lot
    context = {"create_lot": True, "lot_no": new_lot_number}

line_id = get_model("pick.validate.line").create({
    "product_id": product_id,
    "qty": 10,
    "uom_id": uom_id
}, context=context)  # ✅ Respects product rules

# Bad: Force create without checking
context = {"create_lot": True}  # ❌ May violate product rules

3. Use add_line for Container Handling

# Good: Use add_line for containers
result = get_model("pick.validate.line").add_line({
    "pick_id": picking_id,
    "move_id": move_id,
    "qty": 1,
    "uom_id": uom_id
}, context={"container_no": container_number})  # ✅ Handles expansion

# Bad: Manual container expansion
container = get_model("stock.container").search_browse([
    ["number", "=", container_number]
])[0]
for item in container.contents:
    get_model("pick.validate.line").create({...})  # ❌ More complex

Troubleshooting

"Missing lot for product {code}"

Cause: Product requires lot tracking but no lot was specified
Solution: Provide lot_no in context or scan lot barcode

"Not allowed to create new lots for product '{name}'"

Cause: Product has prevent_new_lot=True but trying to create new lot
Solution: Use existing lot numbers only for this product

"Invalid product: product='{name}', container product='{cont_name}'"

Cause: Container contents don't match the product being validated
Solution: Verify correct container or remove container reference

Net weight calculation is None

Cause: qty2 (gross weight) not provided
Solution: Provide qty2 value for weight calculations


Testing Examples

Unit Test: Create Line with Lot

def test_create_line_with_lot():
    # Create line with new lot
    line_id = get_model("pick.validate.line").create({
        "product_id": prod_id,
        "qty": 10,
        "uom_id": uom_id,
        "pick_id": pick_id,
        "move_id": move_id
    }, context={
        "lot_no": "TEST-LOT-001",
        "create_lot": True
    })

    # Verify lot created
    line = get_model("pick.validate.line").browse(line_id)
    assert line.lot_id is not None
    assert line.lot_id.number == "TEST-LOT-001"

Unit Test: Container Expansion

def test_container_expansion():
    # Create container with contents
    cont_id = create_container_with_contents("BOX-001", [
        {"product_id": prod1_id, "qty": 10, "lot_id": lot1_id},
        {"product_id": prod2_id, "qty": 5, "lot_id": lot2_id}
    ])

    # Add line with container
    result = get_model("pick.validate.line").add_line({
        "pick_id": pick_id,
        "move_id": move_id,
        "qty": 1,
        "uom_id": unit_id
    }, context={"container_no": "BOX-001"})

    # Verify multiple lines created
    lines = get_model("pick.validate.line").search([
        ["pick_id", "=", pick_id]
    ])
    assert len(lines) == 2  # One for each product in container

Unit Test: Net Weight Calculation

def test_net_weight():
    # Create packaging and container type
    packaging_id = create_packaging(weight=2.0)  # 2kg per unit
    container_type_id = create_container_type(weight=15.0)  # 15kg

    # Create line with weights
    line_id = get_model("pick.validate.line").create({
        "product_id": prod_id,
        "qty": 5,
        "uom_id": uom_id,
        "qty2": 50.0,  # 50kg gross
        "packaging_id": packaging_id,
        "container_type_id": container_type_id
    })

    # Verify net weight
    line = get_model("pick.validate.line").browse(line_id)
    # Net = 50 - (2 * 5) - 15 = 25kg
    assert line.net_weight == 25.0

Performance Tips

1. Batch Line Operations

# Efficient: Process multiple lines together
wizard = get_model("pick.validate").browse(wizard_id)

updates = []
for line in wizard.lines:
    actual_qty = scan_and_count(line.product_id)
    updates.append((line.id, actual_qty))

# Apply all updates
for line_id, qty in updates:
    line = get_model("pick.validate.line").browse(line_id)
    line.write({"qty": qty})

2. Minimize Lot Lookups

# Efficient: Cache lot lookups
lot_cache = {}

for line_data in lines_to_validate:
    lot_no = line_data["lot_no"]

    if lot_no not in lot_cache:
        # Only lookup once per lot
        res = get_model("stock.lot").search([["number", "=", lot_no]])
        lot_cache[lot_no] = res[0] if res else None

    lot_id = lot_cache[lot_no]
    # Use cached lot_id

Version History

Last Updated: 2025-10-27
Model Version: pick_validate_line.py
Framework: Netforce


Additional Resources

  • Pick Validate Documentation: pick.validate
  • Stock Move Documentation: stock.move
  • Stock Lot Documentation: stock.lot
  • Stock Container Documentation: stock.container
  • Product Documentation: product

This documentation is generated for developer onboarding and reference purposes.