"""User-requested random contract update timestamps, bounded by creation and now."""
|
import sys,json,secrets
|
from pathlib import Path
|
from datetime import timedelta
|
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("SET time_zone='+08:00'")
|
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;now=state['now'];window_start=now-timedelta(days=10)
|
q.execute('SELECT * FROM crm_contract WHERE deleted=0 ORDER BY id FOR UPDATE');before=q.fetchall()
|
backup=P/('contract-update-times-before-'+now.strftime('%Y%m%d-%H%M%S')+'.json')
|
backup.write_text(json.dumps({'state':state,'contracts':before},ensure_ascii=False,default=str,indent=2),encoding='utf8')
|
changes=[];skipped=[];used=set()
|
for old in before:
|
assert old['create_time'] is not None
|
start=max(window_start,old['create_time'])
|
if start>now:skipped.append({'id':old['id'],'reason':'创建时间晚于当前时间,无可用区间,保留原值'});continue
|
span=int((now-start).total_seconds())
|
for attempt in range(100):
|
target=start+timedelta(seconds=secrets.randbelow(span+1))
|
if target not in used or span==0:break
|
assert old['create_time']<=target<=now and target>=window_start
|
used.add(target)
|
q.execute('UPDATE crm_contract SET update_time=%s WHERE id=%s AND deleted=0',(target,old['id']));assert q.rowcount==1
|
changes.append({'id':old['id'],'name':old['name'],'create_time':str(old['create_time']),'old_update_time':str(old['update_time']),'update_time':str(target)})
|
q.execute('SELECT * FROM crm_contract WHERE deleted=0 ORDER BY id');after=q.fetchall();expected={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<=({'update_time'} if old['id'] in expected else set())
|
if old['id'] in expected:assert str(new['update_time'])==expected[old['id']]['update_time'] and max(new['create_time'],window_start)<=new['update_time']<=now
|
c.commit()
|
q.execute('SELECT * FROM crm_contract WHERE deleted=0 ORDER BY id');assert q.fetchall()==after
|
result={'committed':True,'verified':True,'at':str(now),'window_start':str(window_start),'timezone':'Asia/Shanghai','count':len(changes),'changes':changes,'skipped':skipped,'earliest':min((x['update_time'] for x in changes),default=None),'latest':max((x['update_time'] for x in changes),default=None),'backup':backup.name,'other_contract_fields_unchanged':True}
|
(P/'contract-update-times-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()
|