import json,csv,collections
|
from pathlib import Path
|
P=Path(__file__).parent
|
br=json.loads((P/'binding-import-result.json').read_text(encoding='utf8'))
|
pr=json.loads((P/'parameter-station-import-result.json').read_text(encoding='utf8'))
|
b=json.loads((P/'binding-plan-with-ids.json').read_text(encoding='utf8'))
|
p=json.loads((P/'parameter-station-plan-with-ids.json').read_text(encoding='utf8'))
|
s=json.loads((P/'before-binding-snapshot.json').read_text(encoding='utf8'))
|
ss=json.loads((P/'before-station-snapshot.json').read_text(encoding='utf8'))
|
items={i['id']:i for i in s['mes_md_item']}
|
shops={w['id']:w['name'] for w in ss['mes_md_workshop']}
|
lines=['# 生产基础数据补充结果','',
|
'已同步数据库:`mom-hm`。来源为本次生产工艺规程、现有产品及BOM、现有车间和系统参数类型。','',
|
'| 项目 | 数量 |','| --- | ---: |',
|
f"| 产品及小包装半成品路线绑定 | {br['products_bound']} |",
|
f"| 已使用路线(含完整生产、包装段、小包装路线) | {br['routes_used']} |",
|
f"| 本次新增路线变体 | {br['derived_routes_created']} |",
|
f"| 产品BOM工序投入 | {br['direct_bom_inputs']} |",
|
f"| 生产基础参数 | {pr['new_parameters']} |",
|
f"| 参数模板 | {pr['new_templates']} |",
|
f"| 模板参数明细 | {pr['template_details']} |",
|
f"| 路线工序模板绑定 | {pr['route_process_template_bindings']} |",
|
f"| 工序通用参数绑定 | {pr['process_parameter_bindings']} |",
|
f"| 工作站 | {pr['new_workstations']} |",
|
f"| 补充计量单位 | {pr['new_units']} |",
|
'', '## 产品、投入与产出','',
|
'按名称、规格和BOM包装/配方证据匹配,符合条件的多个产品均已绑定。一个产品只绑定一条路线。',
|
'BOM投入保留原比例,每个直接BOM用料只安排到一个工序。已灌装半成品进入包装路线,原料和配方用料进入制造路线。小包装半成品另有生产路线,省略外盒段。',
|
'产出随生产工单产品编码和单位对应。系统空产出配置会原生回退到工单产品;没有将多种成品编码写成固定首项,也没有将整盒工单切换成单袋物料而保留错误数量。',
|
'',f"未自动绑定 {br['pending_unbound_products']} 个产品:",'']
|
for e in b['exceptions']:
|
i=items[e['product_id']];lines.append(f"- {i['code']} {i['name']} {i['specification'] or ''}:{e['reason']}")
|
lines += ['',f"另有 {br['products_without_bom']} 个已绑定产品/半成品未找到自身制造BOM,未虚构投入。24个产品使用已封装半成品BOM,已绑定包装段。即食藜麦粉B型暂未找到明确对应产品,规程路线及参数模板已保留。",'',
|
'## 参数与模板','',
|
'沿用系统数值参数类型,生产要求模板类型1、自检要求类型2。单位复用现有MDM计量单位;补充摄氏度、分钟、秒、兆帕、转/分钟、毫米、百分比、目。',
|
'温度、时间、压力、灌装净含量等明确工艺要求保存在模板参数备注,保留来源规程。带星号工序的明确数值记录项设置必填,未明确的通用记录项不虚构限值。',
|
'', '| 工序 | 文档要求示例 |','| --- | --- |',
|
'| 微波杀菌 | 有机及SG黑果55~65℃、13~15min;DY黑果及袋泡茶50~60℃ |',
|
'| 真空脱气 | -0.07MPa |','| 均质 | 18~20MPa |',
|
'| 瞬时灭菌 | 100℃、30s |','| 热灌装 | ≥87℃;各饮品分别按30/35/50ml或工单小包装规格记录 |',
|
'| 水浴灭菌 | 90℃;30min与40min分别模板,按产品规程绑定 |',
|
'| 预热保温 | 85℃、30min |','| 果膏提取过滤 | 80±5℃,2次、每次15min,120目 |',
|
'| 山药粉过筛 | 80目 |',
|
'', 'R型藜麦粉混合30/40min冲突没有选择统一执行值。B型前处理高温杀菌数值仅见流程图,模板标为待核实。',
|
'现有模板表没有结构化上下限字段,也没有默认生产实测值字段;标准写在备注,实际值由现场填写,系统不会据此自动判定超限。',
|
'', '## 工作站','',
|
'严格按一个去重工序对应一个工作站建立46个工作站,工序名称相同不因产品或车间重复建立。参考现有车间的岗位职责归属,全部关联已有虚拟线边仓、库区和库位。',
|
'工作站已启用;实体地址、设备、人员未虚构,待现场资料补录。现有车间保持不变。','',
|
'| 现有车间 | 工作站数 |','| --- | ---: |']
|
count=collections.Counter(x['workshop_id'] for x in p['stations'])
|
lines += [f'| {shops[k]} | {v} |' for k,v in sorted(count.items())]
|
lines += ['', '## 校验与当前状态','',
|
'事务写入并校验:一工序一工作站、产品唯一绑定、BOM用料无重复且比例一致、单位及模板关联有效、原工序质检标志完整保留、全部非倒冲。',
|
'所有本次工艺路线仍停用,保留手动领料;缺少制造BOM、计量比例及文档参数冲突项见清单。没有生成新的生产工单、报工实测值、领料单或库存流水。',
|
'', '## 文件','',
|
'- 产品路线匹配明细.csv','- 工序投入匹配明细.csv','- 工序产出匹配明细.csv','- 产品绑定及投入待核实清单.csv',
|
'- 工作站与工序车间对应.csv','- 生产参数定义.csv','- 生产参数模板明细.csv','- 路线工序参数模板绑定.csv',
|
'- binding-import-result.json、parameter-station-import-result.json:校验结果',
|
'- before-binding-import.json、before-parameter-station-import.json:写入前快照',
|
'- binding-import-executed.sql、parameter-station-import-executed.sql:实际执行SQL(不含口令)','']
|
(P/'生产基础数据补充说明.md').write_text('\n'.join(lines),encoding='utf8')
|
print(json.dumps({'report':str((P/'生产基础数据补充说明.md').resolve()),'workstations_by_workshop':{shops[k]:v for k,v in sorted(count.items())}},ensure_ascii=False))
|