批次管理基础:批次概念与生命周期
做MES这么多年,我越来越觉得批次管理是物料追踪的灵魂。没有批次,你根本说不清这批料是哪来的、用到哪去了。说白了,批次就是给物料贴上一个「身份证号」,让每一份物料都有迹可循。
什么是批次?
批次,英文叫Lot或Batch。它代表一批在相同条件下生产的物料。比如同一天、同一条产线、同一台设备、同一批原料生产出来的产品,就可以归为一个批次。
我遇到过不少刚入行的朋友问:「批次和序列号有什么区别?」嗯,这个问题很关键。序列号是唯一标识单个产品,而批次标识的是一组产品。你想想看,如果每个螺丝都打序列号,那成本得多高?但用批次管理,一箱螺丝一个批次号,就够用了。
核心区别:
- 批次(Lot):一组物料的集合,共享相同属性
- 序列号(Serial Number):单个物料的唯一标识
- 应用场景:原材料、半成品用批次;关键零部件、成品用序列号
批次的生命周期
一个批次从生到死,大概经历这么几个阶段。我习惯把它画成一条时间线:
每个阶段都有对应的状态管理。我举个例子:
| 阶段 | 状态 | 说明 |
|---|---|---|
| 创建 | 待检验 / 已锁定 | 刚生成的批次,还不能使用 |
| 在库 | 可用 / 冻结 / 预留 | 检验合格后释放,可被生产领用 |
| 投料 | 已领用 / 已消耗 | 批次从仓库转移到产线 |
| 产出 | 已完工 / 已入库 | 生产完成,形成新的批次 |
| 报废 | 已报废 | 质量不合格,批次生命周期终止 |
💡 个人经验:我建议在设计批次状态时,一定要预留「冻结」状态。曾经有个客户,一批原料检验不合格,但系统里没有冻结机制,结果产线照常领用,最后整批产品都要返工。血的教训啊。
批次号生成策略
批次号怎么生成?这问题看似简单,但坑不少。我见过最离谱的批次号是直接用UUID,32位字符串,工人扫码都扫不全。批次号要兼顾可读性、唯一性和扩展性。
策略一:时间戳方案
最常用的方案。格式一般是:YYYYMMDD + 流水号。比如 20250315001,表示2025年3月15日生成的第1个批次。
def generate_batch_by_timestamp():
from datetime import datetime
now = datetime.now()
date_part = now.strftime("%Y%m%d")
# 假设从Redis获取当日流水号
seq = get_daily_sequence(date_part) # 返回001, 002...
return f"{date_part}{seq:03d}"
# 示例输出
print(generate_batch_by_timestamp()) # 20250315001
这个方案的好处是直观,一看就知道是哪天的批次。但有个问题——如果一天产量很大,流水号可能不够用。我建议流水号至少留4位,或者用时分秒来扩展。
策略二:规则引擎方案
当业务复杂了,简单的日期+流水就不够用了。比如你需要区分产线、班次、物料类型。这时候就要用规则引擎。
class BatchRuleEngine:
def __init__(self, rules: dict):
self.rules = rules # 规则配置
def generate(self, context: dict) -> str:
parts = []
for key, rule in self.rules.items():
if key == 'date':
parts.append(context['date'])
elif key == 'line':
parts.append(f"L{context['line_id']:02d}")
elif key == 'shift':
parts.append(f"S{context['shift_id']}")
elif key == 'material':
parts.append(context['material_code'][:4])
elif key == 'seq':
parts.append(f"{context['seq']:04d}")
return "-".join(parts)
# 规则配置示例
rules = {
'date': {'order': 1},
'line': {'order': 2},
'shift': {'order': 3},
'material': {'order': 4},
'seq': {'order': 5}
}
engine = BatchRuleEngine(rules)
context = {
'date': '20250315',
'line_id': 3,
'shift_id': 1,
'material_code': 'RAW001',
'seq': 12
}
print(engine.generate(context)) # 20250315-L03-S1-RAW0-0012
规则引擎的核心优势:
- 灵活配置,不用改代码就能调整批次号格式
- 支持多维度组合,满足不同业务场景
- 可扩展,随时添加新的规则字段
策略三:混合方案(我推荐)
我个人习惯用时间戳+规则引擎的混合方案。简单来说:
- 前缀:固定标识,比如公司代码或工厂代码
- 时间戳:精确到秒或毫秒,保证唯一性
- 业务属性:产线、班次、物料类型等
- 校验位:防止人工录入错误
def generate_hybrid_batch(factory, line, material):
import hashlib
from datetime import datetime
ts = datetime.now().strftime("%Y%m%d%H%M%S")
base = f"{factory}{ts}{line:02d}{material[:4]}"
# 计算校验位
checksum = hashlib.md5(base.encode()).hexdigest()[:2].upper()
return f"{base}{checksum}"
# 示例
print(generate_hybrid_batch("SH", 3, "RAW001"))
# SH2025031514300303RAW0A3
⚠️ 避坑指南:我曾经在一个项目里,批次号用了纯数字+自增ID。结果业务量暴增,ID冲突了。后来改成时间戳+自增,但历史数据又得迁移。所以一开始就要考虑好容量,别等出问题了再改。
批次属性管理
批次号只是标识,真正有价值的是批次属性。你想想看,光知道批次号有什么用?你得知道这批料的供应商、生产日期、质检报告、有效期等等。
属性分类
我把批次属性分成三类:
| 属性类型 | 示例 | 说明 |
|---|---|---|
| 静态属性 | 物料编码、规格型号、供应商 | 批次创建时就确定,不会改变 |
| 动态属性 | 库存数量、库位、状态 | 随业务操作实时更新 |
| 扩展属性 | 质检报告、COA、有效期 | 根据业务需要灵活添加 |
属性管理的数据模型
我建议用「属性模板+属性值」的设计模式。这样不同物料类型可以有不同的属性集合。
class BatchAttributeTemplate:
"""批次属性模板"""
def __init__(self, material_type):
self.material_type = material_type
self.attributes = []
def add_attribute(self, name, data_type, required=False):
self.attributes.append({
'name': name,
'data_type': data_type, # string, int, float, date
'required': required
})
class BatchAttributes:
"""批次属性实例"""
def __init__(self, batch_id, template):
self.batch_id = batch_id
self.template = template
self.values = {}
def set_attribute(self, name, value):
# 校验数据类型
attr_def = next(
(a for a in self.template.attributes if a['name'] == name),
None
)
if not attr_def:
raise ValueError(f"属性 {name} 未定义")
self.values[name] = value
def get_attribute(self, name):
return self.values.get(name)
# 使用示例
template = BatchAttributeTemplate("原材料")
template.add_attribute("供应商", "string", required=True)
template.add_attribute("批次重量", "float", required=True)
template.add_attribute("生产日期", "date", required=True)
template.add_attribute("有效期至", "date", required=True)
batch_attr = BatchAttributes("B20250315001", template)
batch_attr.set_attribute("供应商", "ABC化工")
batch_attr.set_attribute("批次重量", 500.0)
batch_attr.set_attribute("生产日期", "2025-03-15")
batch_attr.set_attribute("有效期至", "2025-09-15")
💡 实战建议:属性管理一定要支持扩展。我做过一个项目,客户一开始只要求5个属性,半年后增加到20个。如果当初设计成硬编码,那改起来就痛苦了。用模板模式,加属性就像加配置一样简单。
属性查询与追溯
批次属性的核心价值在于查询和追溯。比如:
- 查某个供应商的所有批次
- 查某个日期范围内生产的批次
- 查某个质检指标异常的批次
我建议在数据库里给常用属性建索引。特别是供应商、生产日期、状态这些字段,查询频率很高。
-- 批次属性表设计示例
CREATE TABLE batch_attributes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
batch_id VARCHAR(50) NOT NULL,
attr_name VARCHAR(100) NOT NULL,
attr_value VARCHAR(500),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_batch_id (batch_id),
INDEX idx_attr_name (attr_name),
INDEX idx_attr_value (attr_value)
);
-- 查询某个供应商的所有批次
SELECT DISTINCT batch_id
FROM batch_attributes
WHERE attr_name = '供应商'
AND attr_value = 'ABC化工';
嗯,到这里批次管理的基础内容就差不多了。批次号生成、属性管理、生命周期,这三个点搞清楚了,后面做物料追踪就顺了。记住一句话:批次是MES的血液,属性是血液里的信息,两者缺一不可。
公众号:蓝海资料掘金营,微信deep3321