云
昨天 74b0d9c5ab1dc316b29f8525dcffe45225d4c43c
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
import sys,json,csv
from collections import defaultdict
from read_links import P,connect,encode
from plan_links import build
BASE=['crm_customer','erp_sale_order','mes_pro_mps','mes_pro_work_order','mes_pro_task','mes_wm_batch']
def save(path,obj):path.write_text(encode(obj),encoding='utf8')
def main():
 assert not (P/'result.json').exists(),'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-customer-chain-repair-20261015',0) locked");assert q.fetchone()['locked']==1
   before={}
   targets={x['table'] for x in plan['changes']}
   for table in BASE:
    q.execute('SELECT * FROM `'+table+'` WHERE deleted=0 ORDER BY id'+(' FOR UPDATE' if table in targets else ' FOR SHARE'))
    before[table]=q.fetchall()
   backup=P/('locked-before-'+state['now'].strftime('%Y%m%d-%H%M%S')+'.json');save(backup,before)
   original={t:{r['id']:r for r in rows} for t,rows in before.items()}
   expected={t:{id:dict(r) for id,r in rows.items()} for t,rows in original.items()}
   for change in plan['changes']:
    table,id,field=change['table'],change['id'],change['field']
    assert encode(original[table][id])==encode(change['source_before']),f'Source changed {table}/{id}'
    assert change['after'] in original['crm_customer'] and change['before'] not in original['crm_customer']
    expected[table][id][field]=change['after']
   for change in plan['changes']:
    for ev in change['evidence']:
     assert expected[ev['table']][ev['id']][ev['field']]==change['after'],'Upstream customer changed'
   for change in plan['changes']:
    r=original[change['table']][change['id']]
    q.execute('UPDATE `'+change['table']+'` SET `'+change['field']+'`=%s,update_time=%s WHERE id=%s AND deleted=0 AND `'+change['field']+'` <=> %s',
     (change['after'],r['update_time'],change['id'],change['before']))
    assert q.rowcount==1
   for table in BASE:
    q.execute('SELECT * FROM `'+table+'` WHERE deleted=0 ORDER BY id');after={r['id']:r for r in q.fetchall()}
    assert encode(after)==encode(expected[table]),'Unexpected table/field change: '+table
   c.commit()
   result=dict(plan['summary'],committed_at=str(state['now']),backup=str(backup),changed_fields=['client_id'],
    business_dates_status_quantities_amounts_preserved=True,customers_unchanged=True)
   save(P/'result.json',result)
   with (P/'客户关联修复清单.csv').open('w',encoding='utf-8-sig',newline='') as f:
    w=csv.writer(f);w.writerow(['业务表','业务ID','客户ID','客户名称','关联依据'])
    for r in plan['changes']:w.writerow([r['table'],r['id'],r['after'],r['customer_name'],encode(r['evidence'])])
   save(P/'待确认出货检验单.json',plan['unresolved']);print(encode(result))
 except BaseException:c.rollback();raise
 finally:c.close()
if __name__=='__main__':main()