状态:待实施(口径已与主公确认,主公要求后面再改)。确认日期 2026/09/11。 目标文件:
reports/sold_report/daily_report.py。改前直接读本文档即可。
在已售日报的各商家「用户排行榜」sheet 里,加上新客/老客汇总和复购率,让用户维度数据越来越完整。
| 项 | 口径 |
|---|---|
| 新客定义 | 沿用现有 is_new——本店首单即新客:业务日窗口起点(昨 13:00)之前,该 user_id 在本商家 deca_buy_record.purchased_at 无记录 → 当天首次在本商家下单=新客,否则老客 |
| 复购率 | 回头客率 = 老客占比 = 老客数 ÷ 本期下单总人数 = 1 − 新客占比。与新老统计一体,无需新 SQL |
| 展示位置 | 各商家「用户排行榜」sheet 顶部加一行汇总:新客 X / 老客 Y / 复购率 Z%;逐行"新"标记保留 |
| 覆盖商家 | 全部 REAL_BUYER_MIDS(魔都/卡皇/尼卡/文泰/魔都体育)——只有这几家采了 deca_buy_record |
is_new 已经逐行算好:fetch_moddu_user_ranking(daily_report.py:512)每行返回 是否新用户(bool),口径正是"本店首单"。所以顶部汇总只是对现有数据做聚合,不用写新 SQL。_build_user_ranking_sheet(daily_report.py:1316),表头在 daily_report.py:1337:["排名","用户昵称","user_id","参与车数","参与金额","车均消费","新用户"]。daily_report.py:1459(rank_by_mid[mid] = fetch_moddu_user_ranking(...));逐行"新"标记 show_new_flag 目前仅魔都开(daily_report.py:1498),新用户整行淡粉底 FILL_NEWROW=FEF2F2。daily_report.py:79-160:REAL_BUYER_MIDS、MODDU_MID='881226408'、WIN_P=[昨13:00, 今06:00]、TOP_USERS=None(当前不截断)、MERCHANT_SHORT_NAMES。fetch_moddu_user_ranking 额外返回全量新客数。当前返回 (result[:top_n], total_users);新增第 3 个返回值 new_users = 对全量 rows(截断前) 的 is_new 求和。_build_user_ranking_sheet 顶部(标题行下、表头行上)插入汇总行:
新客 = new_users老客 = total_users − new_users复购率 = 老客 / total_users(total_users=0 时显示 —,避免除零)REAL_BUYER_MIDS 都渲染该汇总行(不再限魔都);逐行"新"标记建议一并对所有真实买家商家打开(数据已具备,展示口径统一)。fetch_moddu_user_ranking 返回的 result 是 rows[:top_n] 截断后的行,total_users 才是全窗口买家数。若直接对 result 里的 是否新用户 求和,只得前 top_n 的新客数——一旦将来把 TOP_USERS 设成有限值,新老/复购率就会错。
所以新客数必须在全量 rows(rows[:top_n] 之前)上统计。当前 TOP_USERS=None 不截断,暂时不会暴露,但务必按全量口径写。
deca_buy_record 接入时间不同,历史深度不足会把实际老客误判为新客,复购率偏低。moddu_miss_capture_report.py),进一步压低复购率。deca_buy_record 无金额字段,金额靠 card_count × 团 unit_price 估算(随机团为近似)。REAL_BUYER_MIDS 的用户排行榜 sheet 顶部出现 新客/老客/复购率 汇总行,数字与逐行"新"标记一致(新客数 = 全量行中"新"的条数)。复购率 = 老客数 / 总人数,边界(0 买家)不报错。python daily_report.py 或 run_report_for_date.py <日期> 生成 Excel 校验。