# -*- coding: utf-8 -*- """clean-residue-defix.py — customer-defectfix 终态残留清理 + 复扫 终态目标(任务书 §三.6):非 seed 活跃 e2c-* = 0(活跃=archive_status=0; seed 17 样例白名单外)。清理走正门 POST /api/customer/archive?id=。 落盘:.scratch/customer-defectfix/residue-final.json """ import io, sys, json, time sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') import requests import pymysql BASE = 'http://localhost:8080' ADMIN = '739564171091247104' OUT = '.scratch/customer-defectfix/residue-final.json' ids = json.load(open('.scratch/customer-e2e/seed-ids.json', encoding='utf-8')) SEED = {str(v['id']) for v in ids.get('customers', {}).values()} print(f'seed 白名单 {len(SEED)} 条') 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 scan(): # 口径:archive_status 1=有效 2=已归档(Customer.java L135-137);有效且非 seed = 残留 rows = dbq("SELECT id, customer_no, customer_name, archive_status, create_time " "FROM customer WHERE customer_name LIKE 'e2c-%' ORDER BY create_time") active = [r for r in rows if str(r['id']) not in SEED and int(r['archive_status'] or 0) == 1] return rows, active rows, active = scan() print(f'e2c-* 总数={len(rows)},非 seed 活跃残留={len(active)}') for r in active: print(f" 待清理: {r['id']} {r['customer_name']} no={r['customer_no']} created={r['create_time']}") # archive 正门清理 r = requests.get(f'{BASE}/api/auth/debug/token', params={'userId': ADMIN}, timeout=30) tok = r.json().get('data') tok = tok if isinstance(tok, str) else (tok or {}).get('token') S = requests.Session() S.headers['Authorization'] = f'Bearer {tok}' results = [] for r_ in active: resp = S.post(f'{BASE}/api/customer/archive', params={'id': str(r_['id'])}, timeout=30) body = resp.json() if resp.status_code == 200 else {} ok = resp.status_code == 200 and body.get('code') == 0 results.append({'id': str(r_['id']), 'name': r_['customer_name'], 'archive': ok, 'msg': str(body.get('message'))[:60]}) print(f" archive {r_['customer_name']}: {'OK' if ok else 'FAIL ' + str(body)[:80]}") time.sleep(0.2) # 复扫 rows2, active2 = scan() print(f'\n复扫:非 seed 活跃 e2c-* = {len(active2)}') for r_ in active2: print(f" 仍活跃: {r_['id']} {r_['customer_name']} arch={r_['archive_status']}") report = {'before_active': len(active), 'archived': results, 'after_active': len(active2), 'CLEAN_OK': len(active2) == 0} json.dump(report, open(OUT, 'w', encoding='utf-8'), ensure_ascii=False, indent=2) print('\n== 残留终态', 'CLEAN_OK ✅(非 seed 活跃=0)' if report['CLEAN_OK'] else '仍有残留 ❌', ',证据落盘', OUT, '==')