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:
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:
Computed Fields Functions¶
get_net_weight(ids, context)¶
Calculates net weight by subtracting packaging and container weights from gross weight.
Formula:
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
Related Models¶
| 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.