12 KiB
12 KiB
batch_gxerp.py 批次统计计算规则
apps/wpm/scripts/batch_gxerp.py 用于按 批次号 (batch) 汇总该批次在各工序组下的生产/检验数据,写入 BatchSt.data (JSON),同时维护 first_time / last_time。
一、入参与前置条件
| 参数 | 说明 |
|---|---|
batch |
批次号 |
mgroup_obj |
工序组对象(当前实现未直接使用,仅作为入口签名) |
- 必须存在
BatchSt.objects.get(batch=batch, version=1),否则报错并退出。 - 遍历
Mgroup.objects.all().order_by("sort"),对每个工序组分别统计。 - 仅统计已提交且已出库的报工单:
mlog.submit_time__isnull=False且material_out__isnull=False,并要求need_inout=True。
二、字段命名约定
输出 JSON data 的 key 形式如下(<G> 代表工序组名):
| Key 模式 | 含义 |
|---|---|
批次号 |
批次号 |
<G>_日期 |
该工序组所有报工日期,去重后 ; 拼接 |
<G>_小日期 / <G>_大日期 |
该工序组最早 / 最晚日期(YYYY-MM-DD) |
<G>_操作人 |
操作人姓名去重后 ; 拼接 |
<G>_班次 |
班次名去重后 ; 拼接 |
<G>_count_use |
领用数(来自上游 mlogb_from) |
<G>_count_real |
实际生产数 |
<G>_count_ok |
合格数 |
<G>_count_notok |
不合格数 |
<G>_count_ok_full |
完全合格数 |
<G>_count_pn_jgqbl |
加工前不良数(来自上游 mlogb_from) |
<G>_合格率 |
合格率(%) |
<G>_完全合格率 |
完全合格率(%) |
<G>_缺陷_<缺陷名> |
该工序组的缺陷数量(按缺陷名汇总) |
<G>_缺陷_<缺陷名>_比例 |
缺陷数 / count_real × 100,单位 % |
<G>_加工前_缺陷_<缺陷名> |
上游 mlogb_from 上的缺陷数量 |
<G>_加工前_缺陷_<缺陷名>_比例 |
加工前缺陷数 / count_use × 100,单位 % |
三、主流程:按工序组汇总(普通报工,is_fix=False)
数据源 mlogb1_qs:
Mlogb where mlog.submit_time IS NOT NULL
and material_out IS NOT NULL
and mlog.mgroup = <G>
and mlog.is_fix = False
and batch = <batch>
and need_inout = True
1. 累加规则
对每条 Mlogb:
| 字段 | 累加来源 |
|---|---|
count_use |
mlogb_from.count_use(上游报工子项;若无 mlogb_from 则跳过) |
count_pn_jgqbl |
mlogb_from.count_pn_jgqbl |
count_real |
当前 item.count_real |
count_ok |
当前 item.count_ok |
count_ok_full |
当前 item.count_ok_full or 0 |
count_notok |
当前 item.count_notok or 0 |
操作人 |
mlog.handle_user(最终去重,按 name 拼接) |
日期 |
mlog.handle_date(最终去重排序) |
班次 |
mlog.shift.name |
并记录所有上游 mlogb_from.id 到 mlogb_q_ids,用于"加工前缺陷"统计。
2. 合格率计算
完全合格率 = round(count_ok_full / count_real * 100, 2)
合格率 = round(count_ok / count_real * 100, 2)
decimal.InvalidOperation 异常时(如分母为 0)记 0。
3. 缺陷统计
- 当前工序缺陷:
MlogbDefect.filter(mlogb__in=mlogb1_qs, count__gt=0).values('defect__name').annotate(total=Sum('count'))<G>_缺陷_<name>= total<G>_缺陷_<name>_比例=round(total / count_real * 100, 2)
- 加工前(上游)缺陷:
MlogbDefect.filter(mlogb__id__in=mlogb_q_ids, count__gt=0)...<G>_加工前_缺陷_<name>= total<G>_加工前_缺陷_<name>_比例=round(total / count_use * 100, 2)
4. 日期字段
data[f"{G}_小日期"] = min(日期列表).strftime("%Y-%m-%d") # 最早日期
data[f"{G}_大日期"] = max(日期列表).strftime("%Y-%m-%d") # 最晚日期
最终 <G>_日期 被覆写为去重排序后的字符串(; 拼接)。
四、外观检验返修(is_fix=True)
数据源 mlogb2_qs:
Mlogb where mlog.submit_time IS NOT NULL
and material_out IS NOT NULL
and mlog.mgroup.name = '外观检验'
and mlog.is_fix = True
and batch = <batch>
and need_inout = True
输出字段:
| Key | 计算 |
|---|---|
外观检验_返修_日期 |
报工日期,去重 ; 拼接 |
外观检验_返修_操作人 |
操作人姓名,去重 ; 拼接 |
外观检验_返修_count_real |
Σ count_real |
外观检验_返修_count_ok |
Σ count_ok |
外观检验_返修_count_ok_full |
Σ count_ok_full or 0 |
外观检验_返修_缺陷_<name> |
MlogbDefect 按缺陷名汇总 |
外观检验_返修_缺陷_<name>_比例 |
round(total / 外观检验_返修_count_real * 100, 2) |
五、外观检验车间库存抽检
数据源 ft_qs:
FtestWork where type2 = TYPE2_SOME
and wm.mgroup.name = '外观检验'
and batch = <batch>
and submit_time IS NOT NULL
输出字段:
| Key | 计算 |
|---|---|
外观检验_车间库存抽检_日期 |
test_date 去重 ; 拼接 |
外观检验_车间库存抽检_操作人 |
test_user.name 去重 ; 拼接 |
外观检验_车间库存抽检_count_notok |
Σ count_notok or 0 |
外观检验_车间库存抽检_缺陷_<name> |
FtestworkDefect 按缺陷名汇总(无比例字段) |
六、外观检验汇总指标(仅当存在 外观检验_count_ok 时计算)
| Key | 公式 |
|---|---|
外观检验_总合格数 |
外观检验_count_ok + 外观检验_返修_count_ok(默认0) |
外观检验_总合格率 |
round(外观检验_总合格数 / 外观检验_count_real * 100, 2) |
外观检验_完全总合格数 |
外观检验_count_ok_full + 外观检验_返修_count_ok_full(默认0) |
外观检验_完全总合格率 |
round(外观检验_完全总合格数 / 外观检验_count_real * 100, 2) |
外观检验_直通合格数 |
外观检验_总合格数 - 外观检验_车间库存抽检_count_notok(默认0) |
直通合格率(依赖尺寸检验)
仅当 尺寸检验_合格率 存在时:
外观检验_直通合格率 = round(外观检验_总合格率 * 尺寸检验_合格率 / 100, 2)
外观检验_直通合格率2 = round(外观检验_直通合格数 / 尺寸检验_count_use * 100, 2)
仅当 尺寸检验_完全合格率 存在时:
外观检验_完全直通合格率 = round(外观检验_完全总合格率 * 尺寸检验_完全合格率 / 100, 2)
异常(InvalidOperation / ZeroDivisionError)回退为 0。
七、写回 BatchSt
data经MyJSONEncoder序列化后回填batchst.data。- 调
get_f_l_date(data):扫描所有以_日期结尾的字段,按;拆开后逐个datetime.strptime("%Y-%m-%d")解析为date对象,再取最小/最大并转成上海时区的00:00:00/23:59:59,得到first_time/last_time。无法解析的片段会写日志并跳过。 - 仅当现有
first_time为空或新值更早时更新;last_time反之。 - 调用
batchst.save()持久化。
八、关键依赖与字段含义速查
| 模型字段 | 中文释义 | 来源 |
|---|---|---|
Mlogb.count_use |
领用数 | 报工子项(来自 mlogb_from) |
Mlogb.count_real |
实际生产数 | 报工子项 |
Mlogb.count_ok |
合格数 | count_real - count_notok |
Mlogb.count_ok_full |
完全合格数 | count_real - count_notok_full |
Mlogb.count_notok |
不合格数 | 缺陷 okcate=30 求和 |
Mlogb.count_pn_jgqbl |
加工前不良 | MlogbDefect 中加工前不良求和 |
Mlogb.need_inout |
是否需出入库 | 仅 True 参与统计 |
Mlogb.mlogb_from |
上游报工子项 | 用于追溯领用与加工前缺陷 |
九、已知潜在问题
mgroup_obj入参未使用:当前实现忽略该参数,对所有Mgroup全量遍历。
十、大批直通良率(main 末尾自动触发)
定义
- 大批 = 拆出检验小批的那个批(如
2605-BJ-0023,退火后合批改名产生;外购半成品则为采购入库批)。由BatchLog拆合批关系确定,不依赖批次号命名和工艺路线。 - 直通良率 = 大批下所有子批次
外观检验_直通合格数之和 ÷ 大批白料数(进炉前数量)× 100。
归属锁定(BatchSt.zt_batch)
批次统计完成后(handle_zt):
- 当前批
data含尺寸检验_count_real/外观检验_count_real时解析归属(resolve_zt_big):- 唯一拆批来源(handover split)→ 该来源即大批;
- 合批复检批(如
大批-A-1)→ 所有合批来源归属同一大批时继承;不一致则记日志不归属; - 无任何拆合批上游 → 自身即大批(未拆批直接检验、外购直检)。
- 归属写入
zt_batch(锁定,已锁定的直接复用);随后重算大批(cal_zt_big)。 - 大批自身重算时(有子批
zt_batch指向它)也会触发重算。
分子
BatchSt.filter(zt_batch=大批) 各批 外观检验_直通合格数 之和(+大批自身若有)。子批发现从大批侧沿拆批边/同大批合批边展开(cal_zt_big,支持 -A-1 复检批、多级拆分)。检验前合并的子批无检验数据,天然不重复计数。
分母(白料数,_zt_white_count 回溯)
从大批沿 BatchLog 向上回溯(限深 ZT_MAX_DEPTH=12,按路径防环,跳过合并回自身的整理性边):
- 锚点:批次存在锚点工段(
ZT_ANCHOR_MGROUPS=["黑化"])产出报工时停止,白料数 = 该批锚点工段mlogb_from.count_use(进炉前领用数)。多次黑化的链取离大批最近的一次。 - 分摊(
_zt_source_out_ratio):来源批有多条生产主线流出边(报工改号/拆批/汇入大批格式ZT_BIG_BATCH_RE的合批)时,按各去向数量占比分摊;汇入不良集中批(如黑检片-00)的旁路不占白料份额,使炉后不良计入生产主线分母。单一去向全额传递。 - 边数量:拆批取
Handoverb(batch=目标批),合批取Handoverb(batch=来源批),报工改号取目标产出行的mlogb_from.count_use;无明细时兜底整单数量。 - 外购兜底:无上游谱系且由入库创建 → 白料数 = 入库数量(
MIOItem.count),口径记入库数量。 - 老数据兜底(
_zt_white_legacy):BatchLog 上线前的批次无边,沿BatchSt.handover/mlog创建来源续上回溯,口径记谱系兜底。
缓存与隔离
- 白料数算出后缓存在大批
data(含算不出的负缓存);子批触发的重算直接复用、只重聚合分子。大批自身重算时data重建、缓存失效并重新回溯。上游补改报工后需大批重算或全量回刷才会刷新。 - 总合格数 > 白料数(如白料池循环整理导致回溯不全)→
直通_良率置空并在口径标注谱系异常,记错误日志(2026-06 抽样 120 个大批:116 正常 / 2 异常隔离 / 2 谱系断头不可得)。
输出字段(写入大批 data)
| Key | 含义 |
|---|---|
直通_子批次 |
归属本大批的子批号 ; 拼接 |
直通_总合格数 |
分子 |
直通_白料数 |
分母(不可得为 null) |
直通_良率 |
百分比(不可得/异常为 null) |
直通_口径 |
白料来源口径:黑化领用 / 入库数量 / 谱系兜底 及异常标注 |
部署
python manage.py migrate wpm(新增BatchSt.zt_batch,迁移0133_batchst_zt_batch)。- 历史回刷:
python scripts/correct_batchst.py(对有检验数据的批重跑main,自动完成归属与大批计算)。
十一、修订记录
- 修复
小日期 / 大日期命名与含义反向,小日期取最早日期、大日期取最晚日期;同步修正batch_bxerp.py、batch_gzerp.py中所有同类字段。 get_f_l_date改为先datetime.strptime解析为date对象再比较,移除对字符串字典序的隐式依赖;非法日期片段记录日志后跳过。- 所有合格率/直通率计算的兜底
except同时捕获decimal.InvalidOperation与ZeroDivisionError,以兼容Decimal与原生数值的除零场景;batch_bxerp.py与batch_gzerp.py中仅捕获decimal.InvalidOperation的合格率分支也同步扩展。 - 新增大批直通良率统计(见第十节):
BatchSt加zt_batch归属锁定字段,main末尾自动解析归属并重算大批的直通_白料数 / 直通_总合格数 / 直通_良率 / 直通_口径。