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

# -*- 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()