"""Synchronize quotation names using explicit contract foreign keys.""" import sys,json from pathlib import Path P=Path(__file__).parent sys.stdout.reconfigure(encoding='utf8') sys.path.insert(0,str(P.parent/'iqc-import-20261012/deps')) import pymysql c=pymysql.connect(host='36.213.150.237',port=10000,user='root',password=sys.stdin.readline().strip(),database='mom-hm',charset='utf8mb4',autocommit=False,cursorclass=pymysql.cursors.DictCursor) try: with c.cursor() as q: q.execute('SELECT DATABASE() db,NOW() now,GET_LOCK(%s,10) locked',('sales-ledger-202609',));state=q.fetchone();assert state['db']=='mom-hm' and state['locked']==1 q.execute('SELECT * FROM crm_contract WHERE deleted=0 ORDER BY id FOR UPDATE');contracts=q.fetchall();byid={x['id']:x for x in contracts} q.execute('SELECT * FROM crm_sale_quotation WHERE deleted=0 ORDER BY id FOR UPDATE');before=q.fetchall() path=P/('quotation-name-sync-before-'+state['now'].strftime('%Y%m%d-%H%M%S')+'.json') path.write_text(json.dumps({'state':state,'contracts':contracts,'quotations':before},ensure_ascii=False,default=str,indent=2),encoding='utf8') changes=[];unlinked=[];matched=0 for old in before: ct=byid.get(old['contract_id']) if not ct:unlinked.append({'id':old['id'],'no':old['no'],'reason':'未关联有效合同,保留原名称'});continue assert ct['name'] and ct['name'].strip() and ct['customer_id']==old['customer_id'],('Invalid linked contract',old['id']) matched+=1 if old['name']==ct['name']:continue q.execute('UPDATE crm_sale_quotation SET name=%s,updater=%s,update_time=%s WHERE id=%s AND deleted=0',(ct['name'],'291',state['now'],old['id']));assert q.rowcount==1 changes.append({'id':old['id'],'no':old['no'],'contract_id':ct['id'],'old_name':old['name'],'new_name':ct['name']}) q.execute('SELECT * FROM crm_sale_quotation WHERE deleted=0 ORDER BY id');after=q.fetchall();changed={x['id']:x for x in changes};assert len(before)==len(after) for old,new in zip(before,after): assert old['id']==new['id'];diff={k for k in old if old[k]!=new[k]};assert diff<=({'name','updater','update_time'} if old['id'] in changed else set()) if new['contract_id'] in byid:assert new['name']==byid[new['contract_id']]['name'] q.execute('SELECT * FROM crm_contract WHERE deleted=0 ORDER BY id');assert q.fetchall()==contracts c.commit() q.execute('SELECT * FROM crm_sale_quotation WHERE deleted=0 ORDER BY id');assert q.fetchall()==after result={'committed':True,'verified':True,'at':str(state['now']),'matched':matched,'changed':len(changes),'changes':changes,'unlinked_preserved':unlinked,'backup':path.name,'other_quotation_fields_and_contracts_unchanged':True} (P/'quotation-name-sync-result.json').write_text(json.dumps(result,ensure_ascii=False,indent=2),encoding='utf8') print(json.dumps({k:v for k,v in result.items() if k!='changes'},ensure_ascii=False)) except Exception:c.rollback();raise finally: with c.cursor() as q:q.execute('SELECT RELEASE_LOCK(%s)',('sales-ledger-202609',)) c.close()