gaoluyang
18 小时以前 e40a608ef9bf51db294d8eefada6a8e2e80cebca
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""Refine the visible descriptions of this batch; retain all provenance and log metadata."""
import sys,json
from pathlib import Path
from collections import defaultdict,Counter
from decimal import Decimal
from read_sources import P,connect,encode
 
LABELS={
 'crm_customer':'客户档案','crm_business':'商机信息','crm_sale_quotation':'销售报价',
 'crm_contract':'销售合同','crm_invoice':'开票记录','crm_receivable':'回款记录',
 'crm_receivable_plan':'回款计划','erp_sale_order':'销售订单',
 'mes_pro_mps':'生产主计划','mes_pro_work_order':'生产工单','mes_pro_task':'生产任务',
 'mes_pro_feedback':'生产报工','mes_qc_iqc':'来料检验','mes_qc_ipqc':'过程检验',
 'mes_qc_oqc':'出货检验','mes_wm_sales_notice':'发货通知','mes_wm_product_sales':'销售出库',
 'mes_wm_product_produce':'生产入库','mes_wm_product_issue':'生产领料',
 'mes_wm_misc_receipt':'其他入库','mdm_item':'物料档案','mes_md_item':'物料档案',
 'mes_md_product_bom':'产品BOM','mes_pro_process':'工序信息','mes_pro_route':'工艺路线',
 'mes_md_workstation':'工作站信息','mes_pd_process_param':'生产参数',
 'mes_pd_process_param_template':'参数模板','mes_dv_repair':'设备维修',
 'mes_dv_check_record':'设备点检','mes_dv_mainten_record':'设备保养'}
BANNED=('补充','补录','非原始','原始请求','重建','归属','来源','非真实','演示')
def number(v):
 return format(Decimal(str(v)).normalize(),'f')
def display(table,s,actor,customers,items,machines):
 label=LABELS[table]
 code=s.get('no') or s.get('code') or s.get('param_code') or s.get('template_code')
 name=s.get('name') or s.get('param_name') or s.get('template_name')
 if name and any(x in name for x in BANNED):name=None
 parts=[label+(f'【{code}】' if code else '')+(f':{name}' if name and name!=code else '')]
 def add(k,v):
  if v is not None and v!='':parts.append(f'{k}:{v}')
 def quantity(k,v):
  if v is not None:add(k,number(v))
 if table=='crm_customer':add('负责人',actor)
 elif table.startswith('crm_') or table=='erp_sale_order':
  add('客户',customers.get(s.get('customer_id')))
  add('销售员' if table=='erp_sale_order' else '负责人',actor)
  field={'crm_sale_quotation':'quotation_time','crm_contract':'order_date','crm_invoice':'invoice_time',
   'crm_receivable':'return_time','crm_receivable_plan':'return_time','erp_sale_order':'order_time'}.get(table)
  if field:
   title={'crm_sale_quotation':'报价日期','crm_contract':'合同日期','crm_invoice':'开票日期',
    'crm_receivable':'回款日期','crm_receivable_plan':'计划回款日期','erp_sale_order':'订单日期'}[table]
   add(title,str(s[field])[:10] if s.get(field) else None)
  quantity('计划回款金额(元)' if table=='crm_receivable_plan' else '金额(元)',s.get('price',s.get('total_price')))
 elif table.startswith('mes_qc_'):
  add('产品',items.get(s.get('item_id')));add('检验人员',actor)
  add('检验日期',str(s['inspect_date'])[:10] if s.get('inspect_date') else None)
  quantity('抽检数量',s.get('check_quantity'))
 elif table=='mes_dv_repair':
  add('设备',machines.get(s.get('machinery_id')));add('维修人员',actor)
  add('报修时间',s.get('require_date'))
 elif table in ('mes_dv_check_record','mes_dv_mainten_record'):
  add('设备',machines.get(s.get('machinery_id')))
  add('点检人员' if table=='mes_dv_check_record' else '保养人员',actor)
  add('点检时间' if table=='mes_dv_check_record' else '保养时间',s.get('check_time',s.get('mainten_time')))
 elif table=='mes_pro_feedback':
  add('产品',items.get(s.get('item_id')));add('报工人员',actor);add('报工时间',s.get('feedback_time'))
  quantity('报工数量',s.get('feedback_quantity'))
 elif table in ('mes_pro_mps','mes_pro_work_order','mes_pro_task'):
  add('产品',items.get(s.get('product_id',s.get('item_id'))));add('生产管理员',actor)
  quantity('计划数量',s.get('quantity'))
 elif table.startswith('mes_wm_'):
  add('经办人',actor)
  field={'mes_wm_sales_notice':'sales_date','mes_wm_product_sales':'sales_date','mes_wm_product_produce':'produce_date',
   'mes_wm_product_issue':'issue_date','mes_wm_misc_receipt':'receipt_date'}[table]
  add('业务时间',s.get(field))
 else:
  add('维护人',actor)
  if table=='mes_md_product_bom':
   add('产品',items.get(s.get('item_id')));quantity('用量',s.get('quantity'))
 text=';'.join(parts)+'。'
 assert not any(x in text for x in BANNED),text
 assert len(text)<=2000
 return label,text
 
def main():
 assert not (P/'display-result.json').exists(),'Display refinement already applied'
 plan=json.loads((P/'plan.json').read_text(encoding='utf8'))
 c=connect(sys.stdin.readline().strip())
 try:
  with c.cursor() as q:
   q.execute("SET time_zone='+08:00'")
   q.execute('SELECT DATABASE() db,NOW() now');state=q.fetchone();assert state['db']=='mom-hm'
   q.execute("SELECT GET_LOCK('codex-business-metadata-log-v1',0) locked");assert q.fetchone()['locked']==1
   q.execute('SELECT * FROM system_operate_log ORDER BY id');before=q.fetchall();bytrace={r['trace_id']:r for r in before}
   backup=P/('display-before-'+state['now'].strftime('%Y%m%d-%H%M%S')+'.json')
   backup.write_text(encode(before),encoding='utf8')
   q.execute('SELECT id,nickname FROM system_users WHERE deleted=0');users={r['id']:r['nickname'].strip() for r in q.fetchall()}
   q.execute('SELECT id,name FROM crm_customer WHERE deleted=0');customers={r['id']:r['name'] for r in q.fetchall()}
   q.execute('SELECT id,name FROM mes_md_item WHERE deleted=0');items={r['id']:r['name'] for r in q.fetchall()}
   q.execute('SELECT id,name FROM mes_dv_machinery WHERE deleted=0');machines={r['id']:r['name'] for r in q.fetchall()}
   groups=defaultdict(list);changes=[]
   for r in plan['records']:groups[r['_table']].append(r)
   for table,records in groups.items():
    ids=[r['biz_id'] for r in records]
    q.execute('SELECT * FROM `'+table+'` WHERE deleted=0 AND id IN ('+','.join(['%s']*len(ids))+') FOR SHARE',ids)
    current={r['id']:r for r in q.fetchall()}
    for p in records:
     log=bytrace[p['trace_id']];extra=json.loads(log['extra'])
     assert extra['batch']=='operation-logs-20261015' and extra['reconstructed']
     subtype,action=display(table,current[p['biz_id']],users[log['user_id']],customers,items,machines)
     q.execute('UPDATE system_operate_log SET sub_type=%s,action=%s,update_time=%s WHERE id=%s AND trace_id=%s',
      (subtype,action,log['update_time'],log['id'],log['trace_id']))
     assert q.rowcount==1
     changes.append({'id':log['id'],'trace_id':p['trace_id'],'sub_type':subtype,'action':action})
   q.execute('SELECT * FROM system_operate_log ORDER BY id');after={r['id']:r for r in q.fetchall()};changed={r['id']:r for r in changes}
   assert len(after)==len(before)
   for old in before:
    expected=dict(old)
    if old['id'] in changed:expected.update(sub_type=changed[old['id']]['sub_type'],action=changed[old['id']]['action'])
    assert encode(after[old['id']])==encode(expected),'Unexpected field change'
   c.commit()
   (P/'display-changes.json').write_text(encode(changes),encoding='utf8')
   result={'updated':len(changes),'backup':str(backup),'refined_at':str(state['now']),
    'fields_changed':['sub_type','action'],'other_log_fields_unchanged':True,
    'untouched_logs':len(before)-len(changes),'by_operation':dict(Counter(r['sub_type'] for r in changes))}
   (P/'display-result.json').write_text(encode(result),encoding='utf8');print(encode(result))
 except BaseException:c.rollback();raise
 finally:c.close()
if __name__=='__main__':main()