# 待办:已售报告「用户排行榜」加 新客/老客汇总 + 复购率 > 状态:**待实施**(口径已与主公确认,主公要求后面再改)。确认日期 2026/09/11。 > 目标文件:`reports/sold_report/daily_report.py`。改前直接读本文档即可。 ## 1. 需求 在已售日报的各商家「用户排行榜」sheet 里,加上**新客/老客汇总**和**复购率**,让用户维度数据越来越完整。 ## 2. 已确认口径(2026/09/11 与主公确认) | 项 | 口径 | |---|---| | **新客定义** | 沿用现有 `is_new`——**本店首单即新客**:业务日窗口起点(昨 13:00)之前,该 `user_id` 在本商家 `deca_buy_record.purchased_at` 无记录 → 当天首次在本商家下单=新客,否则老客 | | **复购率** | **回头客率 = 老客占比** = 老客数 ÷ 本期下单总人数 = 1 − 新客占比。与新老统计一体,无需新 SQL | | **展示位置** | 各商家「用户排行榜」sheet **顶部加一行汇总**:`新客 X / 老客 Y / 复购率 Z%`;逐行"新"标记保留 | | **覆盖商家** | 全部 `REAL_BUYER_MIDS`(魔都/卡皇/尼卡/文泰/魔都体育)——只有这几家采了 `deca_buy_record` | ## 3. 现状(改造起点) - **`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`。 ## 4. 实现步骤(建议) 1. **让 `fetch_moddu_user_ranking` 额外返回全量新客数**。当前返回 `(result[:top_n], total_users)`;新增第 3 个返回值 `new_users` = **对全量 `rows`(截断前)** 的 `is_new` 求和。 2. `_build_user_ranking_sheet` 顶部(标题行下、表头行上)插入汇总行: - `新客 = new_users` - `老客 = total_users − new_users` - `复购率 = 老客 / total_users`(`total_users=0` 时显示 `—`,避免除零) 3. 对全部 `REAL_BUYER_MIDS` 都渲染该汇总行(不再限魔都);逐行"新"标记建议一并对所有真实买家商家打开(数据已具备,展示口径统一)。 4. sheet 上注明口径与局限(见第 6 节)。 ## 5. ⚠️ 陷阱:汇总必须基于全量,不能基于 top_n 截断后的行 `fetch_moddu_user_ranking` 返回的 `result` 是 **`rows[:top_n]` 截断后**的行,`total_users` 才是全窗口买家数。若直接对 `result` 里的 `是否新用户` 求和,**只得前 top_n 的新客数**——一旦将来把 `TOP_USERS` 设成有限值,新老/复购率就会错。 所以新客数必须在**全量 `rows`**(`rows[:top_n]` 之前)上统计。当前 `TOP_USERS=None` 不截断,暂时不会暴露,但务必按全量口径写。 ## 6. 数据局限(需在 sheet 注明) - 各家 `deca_buy_record` **接入时间不同**,历史深度不足会把实际老客**误判为新客**,复购率偏低。 - 散户购买记录存在**漏采**(见 `moddu_miss_capture_report.py`),进一步压低复购率。 - `deca_buy_record` **无金额字段**,金额靠 `card_count × 团 unit_price` 估算(随机团为近似)。 - 周报/月报当前**无**用户排行榜,本次只做日报。 ## 7. 验收 - 各 `REAL_BUYER_MIDS` 的用户排行榜 sheet 顶部出现 `新客/老客/复购率` 汇总行,数字与逐行"新"标记一致(新客数 = 全量行中"新"的条数)。 - `复购率 = 老客数 / 总人数`,边界(0 买家)不报错。 - 单跑 `python daily_report.py` 或 `run_report_for_date.py <日期>` 生成 Excel 校验。