fix: GSV聚合修复 — 订单汇总改用aggregate_valid_orders累加多笔有效订单
- 新增 aggregate_valid_orders() 函数:同一账户多笔有效订单 GSV/GMV/退款累加 - 订单号取未退款那笔(多笔未退款取最新) - 产品列多单用+拼接 - Step 4 线索绑单仍用 pick_valid_order() 不变 - 修复 13 个账户漏 GSV ¥23,185 的问题
This commit is contained in:
parent
547bce0c90
commit
36853594c5
@ -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 · 非全额退 · K≥C
|
||||
返回: 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))
|
||||
|
||||
|
||||
@ -13,9 +13,16 @@ metadata:
|
||||
|
||||
# 细水入海 — 销售数据全量刷新
|
||||
|
||||
> **版本:** v2(2026-06-16 定稿 · 陈逸鸫 + Cursor 对齐)
|
||||
> **版本:** v2.1(2026-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]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user