fix: GSV聚合修复 — 订单汇总改用aggregate_valid_orders累加多笔有效订单

- 新增 aggregate_valid_orders() 函数:同一账户多笔有效订单 GSV/GMV/退款累加
- 订单号取未退款那笔(多笔未退款取最新)
- 产品列多单用+拼接
- Step 4 线索绑单仍用 pick_valid_order() 不变
- 修复 13 个账户漏 GSV ¥23,185 的问题
This commit is contained in:
xiaoban 2026-06-17 22:16:00 +08:00
parent 547bce0c90
commit 36853594c5
2 changed files with 87 additions and 13 deletions

View File

@ -533,6 +533,71 @@ def pick_valid_order(orders, clue_date):
return valid[0], True
def aggregate_valid_orders(orders, clue_date):
"""
聚合所有有效订单GSV/GMV/退款 累加订单号取未退款那笔
规则: GSV>0 · 非全额退 · KC
返回: dict aggregated_gsv/gmv/refund, best_trade_no, latest_order
(None, False)
"""
if not orders:
return None, False
valid = []
for o in orders:
gsv = o["gsv"]
pay_amount = o["pay_amount"]
refund_amount = o["refund_amount"]
is_full_refund = (pay_amount > 0 and pay_amount == refund_amount)
if gsv <= 0 or is_full_refund:
continue
pay_dt = o["pay_dt"]
if pay_dt and clue_date:
if pay_dt.strftime("%Y-%m-%d %H:%M:%S") < clue_date:
continue
valid.append(o)
if not valid:
return None, False
# 按时间排序
valid.sort(key=lambda o: o["pay_dt"] or datetime.min, reverse=True)
# GSV/GMV/退款 累加
total_gsv = sum(o["gsv"] for o in valid)
total_gmv = sum(o["pay_amount"] for o in valid)
total_refund = sum(o["refund_amount"] for o in valid)
# 订单号优先取未退款的refund_amount==0多笔取最新
no_refund = [o for o in valid if o["refund_amount"] == 0]
if no_refund:
best_trade_no = no_refund[0]["trade_no"]
else:
# 全部有退款,取退款最少的那笔
valid_by_refund = sorted(valid, key=lambda o: o["refund_amount"])
best_trade_no = valid_by_refund[0]["trade_no"]
# 最新订单信息用于 K/L/M 列
latest = valid[0]
# 产品:去重拼接
products = []
seen_p = set()
for o in valid:
p = o.get("product", "")
if p and p not in seen_p:
products.append(p)
seen_p.add(p)
return {
"aggregated_gsv": total_gsv,
"aggregated_gmv": total_gmv,
"aggregated_refund": total_refund,
"best_trade_no": best_trade_no,
"latest_order": latest,
"products": "+".join(products) if products else latest.get("product", ""),
"valid_count": len(valid),
}, True
def write_sales_sheets(token, all_entries, phone_map, db_info):
now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@ -738,13 +803,14 @@ def write_summary_sheet(token, all_entries, phone_map, db_info):
if not orders:
continue
# 用 pick_valid_order 判断该线索是否有有效
valid_order, is_valid = pick_valid_order(orders, clue_date)
if not is_valid or not valid_order:
# 用 aggregate_valid_orders 聚合所有有效订
agg_result, is_valid = aggregate_valid_orders(orders, clue_date)
if not is_valid or not agg_result:
continue
trade_no = valid_order["trade_no"]
pay_dt = valid_order["pay_dt"]
trade_no = agg_result["best_trade_no"]
latest = agg_result["latest_order"]
pay_dt = latest["pay_dt"]
order_date = f"{pay_dt.month}{pay_dt.day}{pay_dt.strftime('%H:%M:%S')}" if pay_dt else ""
row_data = [
@ -759,18 +825,18 @@ def write_summary_sheet(token, all_entries, phone_map, db_info):
di.get("reg_date", ""), # I: 注册日期
di.get("download_channel", ""), # J: 下载渠道
order_date, # K: 下单日期
valid_order["key_from"], # L: 成交渠道
valid_order["product"], # M: 产品
int(valid_order["pay_amount"]) if valid_order["pay_amount"] > 0 else "", # N: GMV
int(valid_order["refund_amount"]) if valid_order["refund_amount"] > 0 else "", # O: 退款
int(valid_order["gsv"]) if valid_order["gsv"] > 0 else "", # P: GSV
latest["key_from"], # L: 成交渠道
agg_result["products"], # M: 产品(多单用+拼接)
int(agg_result["aggregated_gmv"]) if agg_result["aggregated_gmv"] > 0 else "", # N: GMV(聚合)
int(agg_result["aggregated_refund"]) if agg_result["aggregated_refund"] > 0 else "", # O: 退款(聚合)
int(agg_result["aggregated_gsv"]) if agg_result["aggregated_gsv"] > 0 else "", # P: GSV(聚合)
(f"{di['activation']}体验课" if di.get("activation") in ("A1", "A2") else di.get("activation", "")), # Q: 激活课程
di.get("lesson_progress", ""), # R: 行课进度
di.get("lesson_time", ""), # S: 最近行课时间
di.get("lesson_minutes", 0) or "", # T: 学习时长
datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # U: 更新时间
classify_channel(valid_order["key_from"]), # V: 渠道归属
trade_no, # W: 订单号
classify_channel(latest["key_from"]), # V: 渠道归属
trade_no, # W: 订单号(取未退款那笔)
]
gate_rows.append((trade_no, e["row"], row_data))

View File

@ -13,9 +13,16 @@ metadata:
# 细水入海 — 销售数据全量刷新
> **版本:** v22026-06-16 定稿 · 陈逸鸫 + Cursor 对齐
> **版本:** v2.12026-06-17 · GSV 聚合修复
> **协作契约:** `xhs-ark-dashboard/docs/bot-full-refresh-v2.md`
> **大麦侧主文档:** `xhs-ark-dashboard/docs/damai-full-refresh-skill.md`
>
> ### v2.1 变更2026-06-17
> - **GSV 聚合修复:** 订单汇总 Step 5 改用 `aggregate_valid_orders()` 替代 `pick_valid_order()`
> - 同一账户多笔有效订单 → GSV/GMV/退款 全部累加(不再只取最新一笔)
> - 订单号取未退款那笔(多笔未退款取最新)
> - 产品列多单用 `+` 拼接
> - 线索绑单Step 4仍用 `pick_valid_order()` 不变
## 核心架构规则(写死,不可漂移)
@ -134,6 +141,7 @@ PASS 条件:
### 订单汇总进表条件
- Y=1已在三表筛选汇总默认全是有效单
- GSV>0 · 非全额退 · K≥C
- **同一账户多笔有效订单 → GSV/GMV/退款 累加,订单号取未退款那笔**v2.1 修复)
- 同 X 多进线 → 汇总只保留 1 行
### 渠道归属分类 (Z列) [王虹茗确认 2026-06-15]