"""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()