云
昨天 a87fcc60346dfc799bd3c2cddc7acfffb105cb61
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
"""Atomic native parameter/template/workstation supplementation; preserve production settings."""
import json,sys,collections
from pathlib import Path
P=Path(__file__).parent
sys.path.insert(0,str(P.parent/'iqc-import-20261012/deps'))
import pymysql
p=json.loads((P/'parameter-station-plan.json').read_text(encoding='utf8'))
snap=json.loads((P/'before-parameter-snapshot.json').read_text(encoding='utf8'))
ss=json.loads((P/'before-station-snapshot.json').read_text(encoding='utf8'))
def dump(n,v):(P/n).write_text(json.dumps(v,ensure_ascii=False,indent=2,default=str),encoding='utf8')
def norm(v):return json.loads(json.dumps(v,default=str))
def flag(v):return int.from_bytes(v,'big') if isinstance(v,bytes) else int(v or 0)
c=pymysql.connect(host='36.213.150.237',port=10000,user='root',password=sys.stdin.readline().strip(),database='mom-hm',charset='utf8mb4',cursorclass=pymysql.cursors.DictCursor,connect_timeout=10,read_timeout=60)
log=[];newunits=[];newparams=[];newtemplates=[];newstations=[];newbarcodes=[]
try:
 with c.cursor() as q:
  q.execute('SELECT DATABASE() db');assert q.fetchone()['db']=='mom-hm'
  q.execute("SELECT GET_LOCK('stp-routes-20261012',10) ok");assert q.fetchone()['ok']==1
  c.begin();before={}
  tables=['mdm_unit_measure','mes_pd_process_param','mes_pd_process_param_template','mes_pd_process_param_template_detail','mes_pro_process_param','mes_pro_route_process','mes_md_workshop','mes_md_workstation']
  for t in tables:
   q.execute('SELECT ENGINE FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name=%s',(t,));assert q.fetchone()['ENGINE']=='InnoDB'
   q.execute('SELECT * FROM '+t+' WHERE deleted=0 ORDER BY id FOR UPDATE');before[t]=list(q.fetchall())
   expected=snap.get(t,ss.get(t));assert norm(before[t])==expected,f'{t} changed; review required'
  dump('before-parameter-station-import.json',before)
  def execute(sql,args):log.append(q.mogrify(sql,args)+';');q.execute(sql,args)
  def insert(t,v):
   cols=list(v);sql='INSERT INTO '+t+' (`'+'`,`'.join(cols)+"`,creator,updater) VALUES ("+','.join(['%s']*len(cols))+",'1','1')"
   execute(sql,tuple(v[k] for k in cols));return q.lastrowid
  def many(t,values):
   if not values:return
   cols=list(values[0]);sql='INSERT INTO '+t+' (`'+'`,`'.join(cols)+"`,creator,updater) VALUES ("+','.join(['%s']*len(cols))+",'1','1')"
   args=[tuple(v[k] for k in cols) for v in values];log.extend(q.mogrify(sql,a)+';' for a in args);q.executemany(sql,args)
  unitmap={u['code']:u['id'] for u in before['mdm_unit_measure']}
  for code,name in p['units']:
   if code not in unitmap:
    assert not any(u['name'].strip()==name for u in before['mdm_unit_measure'])
    unitmap[code]=insert('mdm_unit_measure',dict(code=code,name=name,primary_flag=0,primary_id=None,change_rate=1,status=0,remark='生产工艺参数记录单位;单位间未设换算关系。'));newunits.append(unitmap[code])
  q.execute("SELECT value FROM system_dict_data WHERE deleted=0 AND status=0 AND dict_type='mes_pd_param_type'");assert '1' in {r['value'] for r in q.fetchall()}
  q.execute("SELECT value FROM system_dict_data WHERE deleted=0 AND status=0 AND dict_type='mes_pd_template_type'");assert {'1','2'}<={r['value'] for r in q.fetchall()}
  parammap={};existing={r['param_name']:r for r in before['mes_pd_process_param']}
  for d in p['parameters']:
   v=dict(param_code=d['param_code'],param_name=d['param_name'],param_type=1,unit_measure_id=unitmap[d['unit_code']],required=0,remark=d['remark'])
   if d['param_name'] in existing:
    old=existing[d['param_name']];assert old['param_type']==1 and old['unit_measure_id']==v['unit_measure_id'];pid=old['id']
   else:pid=insert('mes_pd_process_param',v);newparams.append(pid)
   d['id']=pid;d['unit_measure_id']=v['unit_measure_id'];parammap[d['key']]=d
  templatemap={}
  for t in p['templates']:
   notes=';'.join(t['notes']);sources='、'.join(t['source_codes'])
   remark=('来源:'+sources+';工序记录模板;标准在明细备注,记录现场实际值,不自动判定超限。'+(';'+notes if notes else ''))[:500]
   t['id']=insert('mes_pd_process_param_template',dict(template_code=t['template_code'],template_name=t['template_name'],template_type=t['template_type'],remark=remark));newtemplates.append(t['id']);templatemap[t['key']]=t['id']
   details=[]
   for d in t['details']:
    param=parammap[d['param_key']]
    standard=d['standard'] or '原文未指定统一数值,记录实际值;不得套用其他产品标准。'
    rem=('要求:'+standard+';'+d['note']+';来源:'+sources+';实际值由现场录入。')[:500]
    details.append(dict(template_id=t['id'],process_param_id=param['id'],param_code=param['param_code'],param_name=param['param_name'],param_type=1,unit_measure_id=param['unit_measure_id'],required=int(d['required']),remark=rem))
   many('mes_pd_process_param_template_detail',details)
  many('mes_pro_process_param',[dict(process_id=b['process_id'],process_param_id=parammap[b['param_key']]['id'],required=0,sort=b['sort'],remark=b['remark']) for b in p['process_parameter_bindings']])
  for b in p['route_template_bindings']:
   row=next(r for r in before['mes_pro_route_process'] if r['route_id']==b['route_id'] and r['process_id']==b['process_id'])
   assert row['param_template_id'] is None
   b['param_template_id']=templatemap[b['template_key']]
   execute("UPDATE mes_pro_route_process SET param_template_id=%s,updater='1' WHERE id=%s",(b['param_template_id'],row['id']))
  # Use native virtual line-side hierarchy. No equipment/worker assignments are invented.
  q.execute('SELECT * FROM mes_wm_warehouse WHERE id=23 AND deleted=0');assert q.fetchone()['code']=='WIP_VIRTUAL_WAREHOUSE'
  q.execute('SELECT * FROM mes_wm_warehouse_location WHERE id=8 AND deleted=0');loc=q.fetchone();assert loc['warehouse_id']==23 and loc['code']=='WIP_VIRTUAL_LOCATION'
  q.execute('SELECT * FROM mes_wm_warehouse_area WHERE id=8 AND deleted=0');area=q.fetchone();assert area['location_id']==8 and area['code']=='WIP_VIRTUAL_AREA'
  q.execute('SELECT * FROM mes_wm_barcode_config WHERE biz_type=602 AND deleted=0');configs=list(q.fetchall());assert len(configs)<=1
  config=configs[0] if configs else None
  for st in p['stations']:
   old=[r for r in before['mes_md_workstation'] if r['process_id']==st['process_id']]
   assert len(old)<=1
   if old:st['id']=old[0]['id']
   else:
    st['id']=insert('mes_md_workstation',st);newstations.append(st['id'])
    if config and config['status']==0 and flag(config['auto_generate_flag']):
     content=(config['content_format'] or '{BUSINESSCODE}').replace('{BUSINESSCODE}',st['code'])
     q.execute('SELECT COUNT(*) n FROM mes_wm_barcode WHERE content=%s AND deleted=0',(content,));assert q.fetchone()['n']==0
     newbarcodes.append(insert('mes_wm_barcode',dict(config_id=config['id'],format=config['format'],biz_type=602,content=content,biz_id=st['id'],biz_code=st['code'],biz_name=st['name'],status=0,remark='新增工作站按已有自动条码配置生成。')))
  # Verify coverage, native snapshots, unit foreign keys and untouched route production flags.
  q.execute('SELECT * FROM mes_md_workstation WHERE deleted=0');stations=list(q.fetchall())
  assert len(stations)==46 and len({st['process_id'] for st in stations})==46
  assert all(st['status']==0 and st['warehouse_id']==23 and st['location_id']==8 and st['area_id']==8 and st['workshop_id'] in {w['id'] for w in before['mes_md_workshop']} for st in stations)
  q.execute('SELECT * FROM mes_pro_route_process WHERE deleted=0 ORDER BY id');actual=list(q.fetchall())
  assert len(actual)==len(before['mes_pro_route_process'])
  expected_bind={(b['route_id'],b['process_id']):b['param_template_id'] for b in p['route_template_bindings']}
  for row,old in zip(actual,before['mes_pro_route_process']):
   assert row['id']==old['id']
   assert row['param_template_id']==expected_bind.get((row['route_id'],row['process_id']),old['param_template_id'])
   for k in ['key_flag','check_flag','backflush_flag','output_item_id','sort','next_process_id','remark']:assert row[k]==old[k]
  q.execute('SELECT * FROM mes_pd_process_param_template_detail WHERE deleted=0');details=list(q.fetchall())
  assert len(details)==sum(len(t['details']) for t in p['templates'])
  assert all(d['process_param_id'] in newparams and d['template_id'] in newtemplates and d['unit_measure_id'] in set(unitmap.values()) and d['param_type']==1 for d in details)
  q.execute('SELECT * FROM mes_pro_process_param WHERE deleted=0');links=list(q.fetchall())
  assert len(links)==len(p['process_parameter_bindings']) and len({(l['process_id'],l['process_param_id']) for l in links})==len(links)
  q.execute('SELECT * FROM mes_md_workshop WHERE deleted=0 ORDER BY id');assert list(q.fetchall())==before['mes_md_workshop']
  result={'database':'mom-hm','new_units':len(newunits),'new_parameters':len(newparams),'new_templates':len(newtemplates),'template_details':len(details),'route_process_template_bindings':len(expected_bind),'process_parameter_bindings':len(links),'new_workstations':len(newstations),'workstation_barcodes':len(newbarcodes),'one_station_per_process':True,'production_flags_and_outputs_preserved':True,'actual_production_values_not_prefilled':True,'existing_workshops_preserved':True,'verified':True}
  c.commit();dump('parameter-station-import-result.json',result);dump('parameter-station-plan-with-ids.json',p)
  (P/'parameter-station-import-executed.sql').write_text('START TRANSACTION;\n'+'\n'.join(log)+'\nCOMMIT;\n',encoding='utf8')
  print(json.dumps(result,ensure_ascii=False));q.execute("SELECT RELEASE_LOCK('stp-routes-20261012')")
except:c.rollback();raise
finally:c.close()