ai_member_xiaoxi/scripts/migrate_old_leads.py
2026-06-02 08:00:01 +08:00

196 lines
8.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""迁移旧销售线索表 → 新表"""
import openpyxl, json, requests, os, sys
OLD_FILE = "/root/.openclaw/media/inbound/é_è½_å_æ_ä_è_-ç_ä_ç_ï¼_è_æ_ï¼_å_溪å_å_ç---7af347cb-3646-4ebc-97a4-a70b9165c363.xlsx"
SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug"
SHEET_IDS = {"吴迪": "f975f0", "小龙": "qJF4I", "成都": "qJF4J"}
CRED_DIR = "/root/.openclaw/credentials/xiaoxi"
def get_fs_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 put_values(token, sheet_id, range_str, values):
url = f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values"
body = {"valueRange": {"range": f"{sheet_id}!{range_str}", "values": values}}
resp = requests.put(url, headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}, json=body, timeout=30)
r = resp.json()
if r.get("code") != 0:
print(f" 写入失败 {range_str}: {r}")
return r
def safe_str(v):
if v is None:
return ""
s = str(v).strip()
# 处理公式残留
if s.startswith("=") or s.startswith("IF("):
return ""
return s
def main():
wb = openpyxl.load_workbook(OLD_FILE, data_only=True)
token = get_fs_token()
for sheet_name in ["吴迪", "小龙", "成都"]:
if sheet_name not in wb.sheetnames:
print(f"⚠️ 未找到 sheet: {sheet_name}")
continue
ws = wb[sheet_name]
sheet_id = SHEET_IDS[sheet_name]
print(f"\n{'='*40}\n迁移 [{sheet_name}] → {sheet_id}")
# 收集有效数据行从第4行开始跳过表头/标注/说明)
rows_out = []
for row_idx in range(4, ws.max_row + 1):
a = safe_str(ws.cell(row=row_idx, column=1).value) # 销售归属
b = safe_str(ws.cell(row=row_idx, column=2).value) # 微信昵称
c = safe_str(ws.cell(row=row_idx, column=3).value) # 进线日期
e = safe_str(ws.cell(row=row_idx, column=5).value) # 手机号
if not a and not b and not e:
continue # 空行跳过
# 旧列 → 新列映射
# A:销售归属 B:微信昵称 C:进线日期 D:体验节数 E:手机号 F:用户年级 G:课史/跟进
d_old = safe_str(ws.cell(row=row_idx, column=4).value) # 体验节数(小溪)
f = safe_str(ws.cell(row=row_idx, column=6).value) # 用户年级
g = safe_str(ws.cell(row=row_idx, column=7).value) # 课史/跟进
h_old = safe_str(ws.cell(row=row_idx, column=8).value) # 用户ID(选填)
w_col = safe_str(ws.cell(row=row_idx, column=23).value) # 匹配uid
# H:用户ID — 优先用匹配uid(W列)其次用户ID(H列)
uid = w_col if w_col else h_old
# 下单信息
i_old = safe_str(ws.cell(row=row_idx, column=9).value) # 下单日期 → L
j_old = safe_str(ws.cell(row=row_idx, column=10).value) # 成交渠道 → M
k_old = safe_str(ws.cell(row=row_idx, column=11).value) # 产品 → N
l_old = safe_str(ws.cell(row=row_idx, column=12).value) # 实付金额 → O
m_old = safe_str(ws.cell(row=row_idx, column=13).value) # 退款金额 → P
# 行课信息
n_old = safe_str(ws.cell(row=row_idx, column=14).value) # 行课状态(自动) → S
o_old = safe_str(ws.cell(row=row_idx, column=15).value) # 最近行课 → T
# 同步时间
y_old = safe_str(ws.cell(row=row_idx, column=25).value) # 同步时间 → V
# 构建新行 (22列 A-V)
new_row = [
a, # A: 销售归属
b, # B: 微信昵称
c, # C: 进线日期
d_old, # D: 体验节数 (保留旧值)
e, # E: 手机号
f, # F: 用户年级
g, # G: 课史/跟进
uid, # H: 用户ID
"", # I: 注册日期 (自动回填)
"", # J: 下载渠道 (自动回填)
"", # K: 是否下单 (自动回填)
i_old, # L: 下单日期
j_old, # M: 成交渠道
k_old, # N: 产品
l_old, # O: 下单金额(GMV)
m_old, # P: 退款金额
"", # Q: 实际收入(GSV) (自动回填)
"", # R: 激活课程 (自动回填)
n_old, # S: 当前行课进度 (旧行课状态)
o_old, # T: 最近行课时间
"", # U: 累计学习时长 (自动回填)
y_old, # V: 更新时间
]
rows_out.append(new_row)
print(f" 有效数据: {len(rows_out)}")
if not rows_out:
continue
# 分批写入飞书API限制每批最多写一定行数
BATCH = 50
for batch_start in range(0, len(rows_out), BATCH):
batch = rows_out[batch_start:batch_start + BATCH]
start_row = 3 + batch_start # 从第3行开始跳过表头和标注行
end_row = start_row + len(batch) - 1
range_str = f"A{start_row}:V{end_row}"
put_values(token, sheet_id, range_str, batch)
print(f" 写入 {range_str} ({len(batch)} 行)")
# ── 订单汇总 sheet ──
if "订单汇总" in wb.sheetnames:
print(f"\n{'='*40}\n迁移 [订单汇总]")
ws = wb["订单汇总"]
rows_out = []
for row_idx in range(4, ws.max_row + 1):
a = safe_str(ws.cell(row=row_idx, column=1).value) # 销售归属
b = safe_str(ws.cell(row=row_idx, column=2).value) # 进线日期
c = safe_str(ws.cell(row=row_idx, column=3).value) # 下单日期
d = safe_str(ws.cell(row=row_idx, column=4).value) # 微信昵称
if not a and not d:
continue
e = safe_str(ws.cell(row=row_idx, column=5).value) # 成交渠道
f = safe_str(ws.cell(row=row_idx, column=6).value) # 产品
g = safe_str(ws.cell(row=row_idx, column=7).value) # 实付金额
h = safe_str(ws.cell(row=row_idx, column=8).value) # 退款金额
i = safe_str(ws.cell(row=row_idx, column=9).value) # 落单渠道
j = safe_str(ws.cell(row=row_idx, column=10).value) # 渠道归属
k = safe_str(ws.cell(row=row_idx, column=11).value) # 订单状态
l = safe_str(ws.cell(row=row_idx, column=12).value) # 有效成单
new_row = [a, b, c, d, e, f, g, h, i, j, k, l]
rows_out.append(new_row)
print(f" 有效数据: {len(rows_out)}")
if rows_out:
# 先创建订单汇总 sheet
# 先看看有没有这个sheet没有就创建
token2 = get_fs_token()
# 创建新 sheet
resp = requests.post(
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/sheets_batch_update",
headers={"Authorization": f"Bearer {token2}", "Content-Type": "application/json"},
json={"requests": [{"addSheet": {"properties": {"title": "订单汇总", "index": 3}}}]},
timeout=15
)
r = resp.json()
print(f" 创建订单汇总sheet: {r.get('code')}")
if r.get("code") == 0:
summary_sheet_id = r["data"]["replies"][0]["addSheet"]["properties"]["sheetId"]
else:
print(f" 创建失败: {r}")
wb.close()
return
# 写表头
headers = [["销售归属","进线日期","下单日期","微信昵称","成交渠道","产品","实付金额(¥)","退款金额","落单渠道","渠道归属","订单状态","有效成单"]]
put_values(token2, summary_sheet_id, "A1:L1", headers)
# 写数据
BATCH = 50
for batch_start in range(0, len(rows_out), BATCH):
batch = rows_out[batch_start:batch_start + BATCH]
start_row = 2 + batch_start
end_row = start_row + len(batch) - 1
range_str = f"A{start_row}:L{end_row}"
put_values(token2, summary_sheet_id, range_str, batch)
print(f" 写入 {range_str} ({len(batch)} 行)")
wb.close()
print("\n✅ 迁移完成!")
if __name__ == "__main__":
main()