You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
5.4 KiB
131 lines
5.4 KiB
# -*- coding: utf-8 -*-
|
|
"""票 05 补采:quick-create 相似分支真值(needConfirm=true + similarHits 非空)。
|
|
|
|
夹具前缀 e2c-t05qc-(独立于 r3d),DB 正门清扫;产物更新 specimens-doc-truth.json 的
|
|
POST /api/customer/quick-create entry(原 entry 为 67001 参数缺失错误信封,不可用作示例)。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pymysql
|
|
import requests
|
|
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
|
|
BASE = 'http://localhost:8080'
|
|
ADMIN = '739564171091247104'
|
|
PFX = 'e2c-t05qc'
|
|
OUT = Path('.scratch/customer-integration-ready/specimens-doc-truth.json')
|
|
S = requests.Session()
|
|
|
|
|
|
def get_token(uid):
|
|
r = requests.get(f'{BASE}/api/auth/debug/token', params={'userId': uid}, timeout=10)
|
|
r.raise_for_status()
|
|
return r.json()['data']
|
|
|
|
|
|
def api(method, path, form=None, params=None, step='', uid=ADMIN):
|
|
headers = {'Authorization': f'Bearer {get_token(uid)}'}
|
|
kw: dict = {'headers': headers, 'timeout': 60}
|
|
if method == 'POST':
|
|
kw['data'] = form or {}
|
|
else:
|
|
kw['params'] = params or {}
|
|
r = S.request(method, BASE + path, **kw)
|
|
try:
|
|
body = r.json()
|
|
except Exception:
|
|
body = {'_raw': r.text[:300], '_status': r.status_code}
|
|
print(f" [{step or path}] http={r.status_code} code={body.get('code') if isinstance(body, dict) else '?'}")
|
|
return r, body
|
|
|
|
|
|
def db():
|
|
return pymysql.connect(host='8.129.84.155', port=3306, user='root', password='Itc@123456',
|
|
database='crm', charset='utf8mb4', autocommit=True,
|
|
connect_timeout=10, cursorclass=pymysql.cursors.DictCursor)
|
|
|
|
|
|
def dbq(sql, args=None):
|
|
with db() as conn, conn.cursor() as cur:
|
|
cur.execute(sql, args)
|
|
return cur.fetchall()
|
|
|
|
|
|
def dbx(sql, args=None):
|
|
with db() as conn, conn.cursor() as cur:
|
|
cur.execute(sql, args)
|
|
return cur.rowcount
|
|
|
|
|
|
def sweep():
|
|
rows = dbq("SELECT id FROM customer WHERE customer_name LIKE %s", (PFX + '%',))
|
|
for row in rows:
|
|
cid = row['id']
|
|
for t in ['customer_contact_edge', 'customer_contact_graph', 'customer_contact_reveal_log',
|
|
'contact_import_task', 'customer_contact', 'customer_oplog',
|
|
'customer_transfer_detail', 'customer_transfer',
|
|
'team_member', 'customer_focus', 'customer_import_fail', 'customer_import_task']:
|
|
try:
|
|
dbx(f"DELETE FROM {t} WHERE customer_id=%s", (cid,))
|
|
except Exception:
|
|
pass
|
|
dbx("DELETE FROM customer WHERE id=%s", (cid,))
|
|
print(f'sweep: 清扫夹具客户 {len(rows)} 组')
|
|
|
|
|
|
# ---------- 1) 源客户 ----------
|
|
sweep()
|
|
SRC_NAME = f'{PFX}-相似源甲科技有限公司'
|
|
r, src = api('POST', '/api/customer/create', form={
|
|
'customerName': SRC_NAME, 'customerType': 'customer_type_01',
|
|
'provinceCode': '440000', 'cityCode': '440100', 'districtCode': '440103',
|
|
'industryCode': 'other', 'customerStarLevel': 3, 'relationStarLevel': 3,
|
|
'isBizNegotiated': 0, 'isChild': 0, 'ownerUserId': ADMIN,
|
|
}, step='create 源客户')
|
|
assert (src.get('data') or {}).get('id'), f'源客户创建失败: {str(src)[:200]}'
|
|
print(f" 源客户 id={src['data']['id']}")
|
|
|
|
# ---------- 2) 相似探测(check-name 三层) ----------
|
|
QC_NAME = f'{SRC_NAME}B' # 仅差尾字符,相似度最高
|
|
r, probe = api('GET', '/api/customer/check-name', params={'name': QC_NAME}, step='check-name 探测')
|
|
print(f" 探测返回: {json.dumps(probe, ensure_ascii=False)[:300]}")
|
|
|
|
# ---------- 3) quick-create 相似分支 ----------
|
|
qc_form = {'customerName': QC_NAME, 'customerType': 'customer_type_01',
|
|
'provinceCode': '440000', 'cityCode': '440100',
|
|
'industryCode': 'other', 'customerStarLevel': 3, 'relationStarLevel': 3}
|
|
r, qc = api('POST', '/api/customer/quick-create', form=qc_form, step='quick-create 相似分支')
|
|
d = qc.get('data') or {}
|
|
print(f" needConfirm={d.get('needConfirm')} similarHits={json.dumps(d.get('similarHits'), ensure_ascii=False)[:300]}")
|
|
|
|
if not d.get('needConfirm'):
|
|
# 兜底:源名原样重发(精确重复必然命中)
|
|
QC_NAME = SRC_NAME
|
|
qc_form = {'customerName': QC_NAME, 'customerType': 'customer_type_01',
|
|
'provinceCode': '440000', 'cityCode': '440100',
|
|
'industryCode': 'other', 'customerStarLevel': 3, 'relationStarLevel': 3}
|
|
r, qc = api('POST', '/api/customer/quick-create', form=qc_form, step='quick-create 精确重复兑底')
|
|
d = qc.get('data') or {}
|
|
print(f" 兜底 needConfirm={d.get('needConfirm')} similarHits={json.dumps(d.get('similarHits'), ensure_ascii=False)[:300]}")
|
|
|
|
# needConfirm=true 未落库;若直落库了(兜底路径)sweep 会清掉
|
|
captured = {'request': {'form': qc_form}, 'response': qc}
|
|
if not d.get('needConfirm'):
|
|
print(' ⚠ 两次尝试均未触发 needConfirm=true——保留实测返回仍写入(直落库分支真值)')
|
|
|
|
# ---------- 4) 更新 specimens-doc-truth.json ----------
|
|
doc = json.loads(OUT.read_text(encoding='utf-8'))
|
|
doc['POST /api/customer/quick-create'] = captured
|
|
OUT.write_text(json.dumps(doc, ensure_ascii=False, indent=1) + '\n', encoding='utf-8')
|
|
print(f" doc-truth 更新: POST /api/customer/quick-create resp_len="
|
|
f"{len(json.dumps(qc, ensure_ascii=False))}")
|
|
|
|
# ---------- 5) 清扫 ----------
|
|
sweep()
|
|
print('== 补采完成 ==')
|
|
|