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.
155 lines
6.2 KiB
155 lines
6.2 KiB
# -*- coding: utf-8 -*-
|
|
"""票 10-N3g:新端点真值采集(project/page + detail-head.projectCount + graph/detail 两字段)。
|
|
|
|
夹具:DB 预置 crm_project 一行(e2c-r3d-n3- 前缀,采集后删除);
|
|
图谱联系人 isInternal/giftRemark 临时改值(先存原值,采集后还原)。
|
|
产物:specimens-proj-truth.json('METHOD /path' → {request, response},与套件 specimens 同构)。
|
|
"""
|
|
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' # 罗伟健
|
|
OUT = Path('.scratch/customer-integration-ready')
|
|
PROJ_ID = 193400000000000001
|
|
PROJ_NAME = 'e2c-r3d-n3-项目甲'
|
|
GRAPH_CUSTOMER = 753314901191032832 # 图谱 seed 客户(e2e-graph 夹具所属)
|
|
|
|
specimens: dict[str, dict] = {}
|
|
|
|
|
|
def capture(method, path, req, resp):
|
|
specimens[f'{method} {path}'] = {'request': req, 'response': resp}
|
|
|
|
|
|
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, params=None, form=None, step='', uid=ADMIN):
|
|
headers = {'Authorization': f'Bearer {get_token(uid)}'}
|
|
kw = {'headers': headers, 'timeout': 60}
|
|
if method == 'POST':
|
|
kw['data'] = form or {}
|
|
else:
|
|
kw['params'] = params or {}
|
|
r = requests.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 cols(table):
|
|
return {r['Field']: r for r in dbq(f'DESCRIBE {table}')}
|
|
|
|
|
|
def main():
|
|
# 0) 前置健康:debug token 可用
|
|
print('== 0) token =', get_token(ADMIN)[:16], '...')
|
|
|
|
# 1) 挑 seed 活跃客户(e2c- 前缀、owner=ADMIN)
|
|
rows = dbq("SELECT id, customer_name FROM customer WHERE customer_name LIKE %s "
|
|
"AND owner_user_id=%s ORDER BY id LIMIT 5", ('e2c%', ADMIN))
|
|
if not rows:
|
|
print('!! 无 e2c- seed 客户'); return
|
|
cust = rows[0]
|
|
print(f"== 1) 夹具客户 {cust['id']} {cust['customer_name']}")
|
|
|
|
# 2) DB 预置 crm_project(列名按 DESCRIBE 过滤,缺列跳过)
|
|
want = {
|
|
'id': PROJ_ID, 'project_name': PROJ_NAME, 'project_stage': 0, 'project_status': 1,
|
|
'filing_status': 1, 'bid_result': 0, 'scheme_card_id': 193400000000000002,
|
|
'customer_id': cust['id'], 'owner_user_id': ADMIN, 'owner_name_snapshot': '罗伟健',
|
|
'project_amount': 123456.78, 'creator_id': ADMIN, 'updater_id': ADMIN, 'deleted': 0,
|
|
}
|
|
have = cols('crm_project')
|
|
if 'create_time' in have: want['create_time'] = 'NOW()'
|
|
if 'update_time' in have: want['update_time'] = 'NOW()'
|
|
names, vals = [], []
|
|
for k, v in want.items():
|
|
if k not in have:
|
|
print(f' (跳过不存在列 {k})'); continue
|
|
names.append(k)
|
|
vals.append(v) # NOW() 字符串由下方拼 SQL 处理
|
|
# NOW() 需要裸拼;其余参数化
|
|
col_sql = ', '.join(names)
|
|
ph = ', '.join('NOW()' if isinstance(v, str) and v == 'NOW()' else '%s' for v in vals)
|
|
real = [v for v in vals if not (isinstance(v, str) and v == 'NOW()')]
|
|
dbx(f'INSERT INTO crm_project ({col_sql}) VALUES ({ph})', real)
|
|
print(f'== 2) crm_project 夹具行 id={PROJ_ID}')
|
|
|
|
try:
|
|
# 3) 新端点:关联项目页签
|
|
_, b1 = api('GET', '/api/customer/project/page', params={'id': cust['id'], 'current': 1, 'size': 10},
|
|
step='project/page')
|
|
capture('GET', '/api/customer/project/page', {'id': str(cust['id']), 'current': 1, 'size': 10}, b1)
|
|
|
|
# 4) detail-head:projectCount 真值
|
|
_, b2 = api('GET', '/api/customer/detail-head', params={'id': cust['id']}, step='detail-head')
|
|
print(' projectCount =', (b2.get('data') or {}).get('projectCount'))
|
|
capture('GET', '/api/customer/detail-head', {'id': str(cust['id'])}, b2)
|
|
|
|
# 5) 图谱两字段:联系人临时改值 → 采集 → 还原
|
|
contacts = dbq('SELECT id, is_internal, gift_remark FROM customer_contact '
|
|
'WHERE customer_id=%s ORDER BY id LIMIT 1', (GRAPH_CUSTOMER,))
|
|
if contacts:
|
|
c0 = contacts[0]
|
|
orig = (c0['is_internal'], c0['gift_remark'])
|
|
print(f"== 3) 图谱联系人 {c0['id']} 原值 is_internal={orig[0]} gift={orig[1]!r}")
|
|
dbx('UPDATE customer_contact SET is_internal=1, gift_remark=%s WHERE id=%s',
|
|
('e2c-r3d-n3-礼品-龙井茶两盒', c0['id']))
|
|
try:
|
|
_, b3 = api('GET', '/api/customer/contact/graph/detail',
|
|
params={'customerId': GRAPH_CUSTOMER}, step='graph/detail')
|
|
capture('GET', '/api/customer/contact/graph/detail', {'customerId': str(GRAPH_CUSTOMER)}, b3)
|
|
finally:
|
|
dbx('UPDATE customer_contact SET is_internal=%s, gift_remark=%s WHERE id=%s',
|
|
(orig[0], orig[1], c0['id']))
|
|
print(' 已还原')
|
|
else:
|
|
print('!! 图谱客户无联系人,graph 真值跳过(E2E 重跑后另行回填)')
|
|
|
|
finally:
|
|
# 6) 清理夹具行
|
|
n = dbx('DELETE FROM crm_project WHERE id=%s', (PROJ_ID,))
|
|
print(f'== 6) 夹具清理 crm_project deleted={n}')
|
|
|
|
(OUT / 'specimens-proj-truth.json').write_text(
|
|
json.dumps(specimens, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
print('== specimens-proj-truth.json 落盘,', len(specimens), '条')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|