# -*- coding: utf-8 -*- """票 12 不符③④⑤冒烟(跨机器脱敏版;凭据一律走环境变量)。 必备环境变量: CRM_TOKEN Bearer token(经 crm-auth 登录接口获取;不落任何文件) 可选: CRM_BASE 默认 http://localhost:8080 CRM_DB_HOST/CRM_DB_PORT/CRM_DB_USER/CRM_DB_PASSWORD/CRM_DB_NAME 直连库做逐拍校验,默认 127.0.0.1:3306 / root / crm CRM_SMOKE_CID 复用既有客户 id 跳过 quick-create(重复跑/换库时用) PowerShell 示例: $env:CRM_TOKEN='...'; $env:CRM_DB_HOST='...'; $env:CRM_DB_PASSWORD='...' python .scratch/customer-module/tools/smoke-t12m.py """ import json import os import time import urllib.parse import urllib.request BASE = os.environ.get('CRM_BASE', 'http://localhost:8080') token = os.environ.get('CRM_TOKEN') assert token, '缺 CRM_TOKEN 环境变量(Bearer token,经登录接口获取)' def call(method, path, form=None): url = BASE + path headers = {'Authorization': 'Bearer ' + token} body = None if form is not None: body = urllib.parse.urlencode(form).encode('utf-8') headers['Content-Type'] = 'application/x-www-form-urlencoded' req = urllib.request.Request(url, data=body, headers=headers, method=method) with urllib.request.urlopen(req) as resp: return json.loads(resp.read().decode('utf-8')) import pymysql conn = pymysql.connect(host=os.environ.get('CRM_DB_HOST', '127.0.0.1'), port=int(os.environ.get('CRM_DB_PORT', '3306')), user=os.environ.get('CRM_DB_USER', 'root'), password=os.environ.get('CRM_DB_PASSWORD', ''), database=os.environ.get('CRM_DB_NAME', 'crm'), charset='utf8mb4') def db_focus(cid): cur = conn.cursor() cur.execute("SELECT COUNT(*), IFNULL(SUM(starred), -1) FROM customer_focus WHERE customer_id = %s", (str(cid),)) row = cur.fetchone() print(' db customer_focus rows=%s starred_sum=%s' % (row[0], row[1])) return row cid = os.environ.get('CRM_SMOKE_CID') if not cid: r = call('POST', '/api/customer/quick-create', { 'customerName': '星辰大海贸易有限公司' + time.strftime('%H%M%S'), 'customerType': 'TYPE_A', 'provinceCode': '310000', 'cityCode': '310100', 'industryCode': 'I', 'customerStarLevel': '3', 'relationStarLevel': '2', 'confirmSimilar': 'true', }) print('quick-create code:', r.get('code')) cid = (r.get('data') or {}).get('id') if not cid: print('quick-create response:', json.dumps(r, ensure_ascii=False)[:600]) raise SystemExit('ABORT: no cid (dup-check hit? 换 CRM_SMOKE_CID 复用或改名重跑)') print('cid:', cid) # 67002 校验:客户不存在 r404 = call('POST', '/api/customer/999999999/focus') print('focus unknown-cust code (expect 67002):', r404.get('code')) # ③ focus 幂等 print('focus#1 code:', call('POST', '/api/customer/%s/focus' % cid)['code']) db_focus(cid) print('focus#2 code:', call('POST', '/api/customer/%s/focus' % cid)['code']) db_focus(cid) # star 幂等(含已关注行原位置 1) print('star#1 code:', call('POST', '/api/customer/%s/star' % cid)['code']) db_focus(cid) print('star#2 code:', call('POST', '/api/customer/%s/star' % cid)['code']) db_focus(cid) # focus-batch 幂等(批量传自身) rb = call('POST', '/api/customer/focus-batch?' + urllib.parse.urlencode({'ids': '%s,%s' % (cid, cid)})) print('focus-batch code:', rb.get('code')) db_focus(cid) # unstar(保留行) print('unstar code:', call('POST', '/api/customer/%s/unstar' % cid)['code']) db_focus(cid) # unfocus(物理删行) print('unfocus code:', call('POST', '/api/customer/%s/unfocus' % cid)['code']) db_focus(cid) # ④ detail-head 占位字段恒 null d = call('GET', '/api/customer/%s/detail-head' % cid)['data'] keys = ['wonProjectAmount', 'planEstimateAmount', 'ongoingOpportunityAmount', 'contractAmount', 'paidAmount'] print('detail-head placeholder nulls:', {k: d.get(k) for k in keys}) # ⑤ oplog action 过滤 op_all = call('GET', '/api/customer/%s/oplog/page' % cid)['data'] op_c = call('GET', '/api/customer/%s/oplog/page?action=CREATE' % cid)['data'] op_u = call('GET', '/api/customer/%s/oplog/page?action=UPDATE' % cid)['data'] print('oplog all total=%s actions=%s' % (op_all['total'], [row['action'] for row in op_all['content']])) print('oplog action=CREATE total=%s' % op_c['total']) print('oplog action=UPDATE total=%s (expect 0)' % op_u['total']) conn.close() print('SMOKE DONE')