ai_member_xiaoxi/scripts/sync_weiban_to_sales.py
2026-06-04 08:00:01 +08:00

146 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""同步微伴线索到销售表,去重后追加"""
import json, requests, os, sys
from collections import defaultdict
CRED_DIR = "/root/.openclaw/credentials/xiaoxi"
SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug"
WEIBAN_FILE = "/tmp/weiban_20260603.xlsx"
# Sheet IDs
SHEET_IDS = {"小龙": "qJF4I", "吴迪": "f975f0"}
# 微伴客服 → 销售映射
CS_MAP = {"益达老师": "小龙", "吴迪": "吴迪"}
def get_token():
with open(os.path.join(CRED_DIR, "config.json")) as f:
cfg = json.load(f)
resp = requests.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": cfg["apps"][0]["appId"], "app_secret": cfg["apps"][0]["appSecret"]},
timeout=15)
return resp.json()["tenant_access_token"]
def read_sheet(token, sheet_id, range_str):
resp = requests.get(
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values/{sheet_id}!{range_str}",
headers={"Authorization": f"Bearer {token}"}, timeout=30)
data = resp.json()
if data.get("code") != 0:
print(f" Read error: {data}")
return []
return data["data"]["valueRange"]["values"]
def append_rows(token, sheet_id, rows):
"""Append rows to sheet using append API"""
url = f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values_append"
body = {"valueRange": {"range": f"{sheet_id}!A:K", "values": rows}}
resp = requests.post(url, headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}, json=body, timeout=30)
r = resp.json()
if r.get("code") != 0:
print(f" Append error: {r}")
return False
return True
def main():
token = get_token()
# Step 1: Parse 微伴 data
print("=== Step 1: 解析微伴数据 ===")
import openpyxl
wb = openpyxl.load_workbook(WEIBAN_FILE, read_only=True)
ws = wb['Sheet1']
weiban_entries = []
for row in ws.iter_rows(min_row=6, values_only=True):
if row[0] is None:
continue
add_time = str(row[13]) if row[13] else ''
if not add_time.startswith('2026-06'):
continue
kefu = row[6] # 所属客服
sales = CS_MAP.get(kefu)
if not sales:
continue
# Parse date: "2026-06-01 12:34:56" → "6月1日"
from datetime import datetime
try:
dt = datetime.strptime(add_time, "%Y-%m-%d %H:%M:%S")
date_str = f"{dt.month}{dt.day}"
except:
date_str = add_time[:10]
name = str(row[0]).strip() if row[0] else ''
weiban_entries.append({
"name": name,
"date": date_str,
"sales": sales,
"kefu": kefu,
})
print(f" 微伴6月线索: {len(weiban_entries)}")
# Count by sales
by_sales = defaultdict(list)
for e in weiban_entries:
by_sales[e["sales"]].append(e)
for s, entries in by_sales.items():
print(f" {s}: {len(entries)}")
# Step 2: Read existing sales sheet data
print("\n=== Step 2: 读取销售表现有数据 ===")
existing_names = {"小龙": set(), "吴迪": set()}
for sales_name, sheet_id in SHEET_IDS.items():
data = read_sheet(token, sheet_id, f"A1:K2000")
for row in data[1:]: # skip header
if row and len(row) >= 2 and row[1]:
name = str(row[1]).strip()
if name:
existing_names[sales_name].add(name)
print(f" {sales_name}表已有 {len(existing_names[sales_name])} 条记录")
# Step 3: Dedup and prepare new rows
print("\n=== Step 3: 去重 ===")
new_rows = {"小龙": [], "吴迪": []}
for sales_name, entries in by_sales.items():
existing = existing_names[sales_name]
for e in entries:
if e["name"] not in existing:
# Format: [销售归属, 微信昵称, 进线日期, 体验节数, 手机号, 用户年级, 课史/跟进, 用户ID, 注册日期, 下载渠道, 是否下单]
new_rows[sales_name].append([sales_name, e["name"], e["date"], "", "", "", "", "", "", "", ""])
else:
print(f" 跳过重复: [{sales_name}] {e['name']}")
for s, rows in new_rows.items():
print(f" {s}新增: {len(rows)}")
# Step 4: Write to sheets
print("\n=== Step 4: 写入销售表 ===")
for sales_name, rows in new_rows.items():
if not rows:
print(f" {sales_name}: 无新增,跳过")
continue
sheet_id = SHEET_IDS[sales_name]
ok = append_rows(token, sheet_id, rows)
if ok:
print(f" {sales_name}: ✅ 写入 {len(rows)}")
else:
print(f" {sales_name}: ❌ 写入失败")
# Step 5: Summary
print("\n=== 汇总 ===")
print(f"微伴6月总量: {len(weiban_entries)}")
print(f"小龙: 微伴{len(by_sales['小龙'])}条 → 新增{len(new_rows['小龙'])}")
print(f"吴迪: 微伴{len(by_sales['吴迪'])}条 → 新增{len(new_rows['吴迪'])}")
if __name__ == "__main__":
main()