1. Revenue 口径统一为 actual_amount(真实现金到账)
- 优惠券(discount_amount)和积分(points_amount)是平台免费发放的营销补贴,
不算收入,改为展示字段
- 涉及: profit_metrics.go, dashboard_spending.go, users_profit_loss.go,
dashboard_user_spending.go, activity_rankings_admin.go
2. Cost 口径统一为奖品库存价值
- 删除 finance service 中的积分成本扫描(Step 3)和优惠券成本扫描(Step 4)
- 之前优惠券同时算在收入和成本两侧,导致利润被人为压低
- 涉及: query_user.go, query_activity.go
3. 统一 value_cents fallback chain
- finance service 改为与排行榜一致的三级回退:
COALESCE(NULLIF(value_cents,0), price_snapshot_cents, products.price, 0)
- 涉及: query_user.go, query_activity.go
4. 活动盈亏收入统一到 finance service
- 删除 dashboard_activity.go 自有的 revenue SQL(含比例分摊逻辑)
- 收入和成本统一由 finance.Service.QueryActivityProfitLoss() 提供
- 修复日志明细 profit:道具卡倍率改用 ComputePrizeCostWithMultiplier
5. finance service 新增展示字段
- ProfitLossDetail 增加 CouponDiscount, PointsDiscount, GamePassValue
- 不参与 Revenue/Cost/Profit 计算,仅供前端展示营销补贴明细
6. 修复对对碰次卡订单 discount_amount 数据污染
- matching_game_app.go 次卡下单时 DiscountAmount 错误设为活动全价
- 改为 0(次卡支付不涉及优惠券)
- 附带历史数据修复 migration SQL
7. 排除已分解奖品的成本重复计算
- 用户可以把奖品分解成积分再兑换新商品,导致同一份价值被计算两次
- 所有库存查询增加排除条件: status=3 且 remark 含 redeemed_points 或 batch_redeemed
- 涉及 6 个文件的库存成本/资产查询
8. 排行榜详情抽屉限定活动范围
- prize 查询增加 activity_id > 0 过滤,排除积分兑换/转入/合成等非活动产出
- 使排行榜与其详情抽屉口径一致
修改文件(12个):
- internal/service/finance/profit_metrics.go
- internal/service/finance/query_user.go
- internal/service/finance/query_activity.go
- internal/service/finance/types.go
- internal/api/admin/dashboard_activity.go
- internal/api/admin/dashboard_spending.go
- internal/api/admin/dashboard_user_spending.go
- internal/api/admin/users_profit_loss.go
- internal/api/admin/users_profile.go
- internal/api/admin/activity_rankings_admin.go
- internal/api/activity/matching_game_app.go
- migrations/20260325_fix_matching_gamepass_discount.sql
25 lines
989 B
SQL
25 lines
989 B
SQL
-- 修复对对碰次数卡订单的幽灵 discount_amount
|
||
-- 问题:matching_game_app.go 中次数卡下单时,DiscountAmount 被错误地设为活动全价
|
||
-- 实际上次数卡支付不涉及优惠券,discount_amount 应该为 0
|
||
-- 影响:所有 discount_amount 汇总统计会虚高
|
||
-- 代码修复:matching_game_app.go L175 DiscountAmount: activity.PriceDraw → 0
|
||
|
||
-- Step 1: 先查看受影响的数据量(DRY RUN)
|
||
-- SELECT COUNT(*) as affected_count,
|
||
-- SUM(discount_amount) as total_phantom_discount_cents,
|
||
-- SUM(discount_amount) / 100.0 as total_phantom_discount_yuan
|
||
-- FROM orders
|
||
-- WHERE source_type = 3
|
||
-- AND actual_amount = 0
|
||
-- AND discount_amount > 0
|
||
-- AND (order_no LIKE 'GP%' OR remark LIKE '%game_pass%');
|
||
|
||
-- Step 2: 执行修复
|
||
UPDATE orders
|
||
SET discount_amount = 0,
|
||
updated_at = NOW(3)
|
||
WHERE source_type = 3
|
||
AND actual_amount = 0
|
||
AND discount_amount > 0
|
||
AND (order_no LIKE 'GP%' OR remark LIKE '%game_pass%');
|