fix: 修复美团订单时间入库并校准金币大盘口径

改了什么:补全美团订单时间戳转换,避免 pay_time 为空导致昨日 CPS 收益漏算;同时让金币经济的本期/累计发放总数按领券、比价、激励视频、常规任务四项加总。
为什么改:产品核对发现昨日美团有收益但大盘未显示,且发放金币总数与分类卡片不一致。
验证方式:后端聚合自检确认 2026-06-30 美团佣金 86 分、有效订单 2 单,金币总数等于四项分类之和;py_compile 通过。
This commit is contained in:
lowmaster-chen
2026-07-01 14:56:22 +08:00
parent a7d8562ddd
commit 21fc930c0a
2 changed files with 91 additions and 9 deletions
+21 -1
View File
@@ -51,7 +51,27 @@ def _yuan_to_cents(v: object) -> int | None:
def _ts_to_dt(ts: object) -> datetime | None:
"""秒级时间戳 → tz-aware UTC datetime(绝对时刻,前端按北京展示)。"""
if not ts:
if ts is None:
return None
if isinstance(ts, datetime):
return ts if ts.tzinfo else ts.replace(tzinfo=_BJ_TZ).astimezone(timezone.utc)
s = str(ts).strip()
if not s or s.lower() == "null":
return None
try:
seconds = float(Decimal(s))
except (InvalidOperation, ValueError):
return None
if seconds == 0:
return None
# 美团文档是秒级时间戳,这里顺手兼容毫秒/微秒,避免上游格式变化导致时间再次落空。
if abs(seconds) > 10_000_000_000_000:
seconds /= 1_000_000
elif abs(seconds) > 10_000_000_000:
seconds /= 1_000
try:
return datetime.fromtimestamp(seconds, tz=timezone.utc)
except (OverflowError, OSError, ValueError):
return None
+70 -8
View File
@@ -24,11 +24,13 @@ from app.models.user import User
from app.models.wallet import CoinTransaction, WithdrawOrder
_BEIJING = timezone(timedelta(hours=8))
COUPON_REWARD_BIZ_TYPES = ("reward_video", "ad_reward", "coupon", "coupon_reward")
REWARD_VIDEO_BIZ_TYPES = ("reward_video", "ad_reward")
COUPON_REWARD_BIZ_TYPES = ("coupon", "coupon_reward")
COMPARISON_REWARD_BIZ_TYPES = ("comparison", "compare_reward", "comparison_reward")
EXCLUDED_REWARD_BIZ_TYPES = ("invite_inviter", "invite_invitee", "admin_grant")
UNCLASSIFIED_FEED_BIZ_TYPES = ("feed_ad_reward",)
REGULAR_TASK_EXCLUDED_BIZ_TYPES = (
*REWARD_VIDEO_BIZ_TYPES,
*COUPON_REWARD_BIZ_TYPES,
*COMPARISON_REWARD_BIZ_TYPES,
*EXCLUDED_REWARD_BIZ_TYPES,
@@ -339,13 +341,28 @@ def dashboard_overview(
period_reward_video_coin_total = _sum(
CoinTransaction.amount,
*period_coin_conds,
CoinTransaction.biz_type.in_(("reward_video", "ad_reward")),
CoinTransaction.biz_type.in_(REWARD_VIDEO_BIZ_TYPES),
)
period_feed_ad_coin_total = _sum(
CoinTransaction.amount,
*period_coin_conds,
CoinTransaction.biz_type == "feed_ad_reward",
)
period_feed_ad_conds = (
AdFeedRewardRecord.created_at >= start_utc,
AdFeedRewardRecord.created_at < end_utc,
AdFeedRewardRecord.status == "granted",
)
period_coupon_feed_coin_total = _sum(
AdFeedRewardRecord.coin,
*period_feed_ad_conds,
AdFeedRewardRecord.feed_scene == "coupon",
)
period_comparison_feed_coin_total = _sum(
AdFeedRewardRecord.coin,
*period_feed_ad_conds,
AdFeedRewardRecord.feed_scene == "comparison",
)
period_signin_coin_total = _sum(
CoinTransaction.amount,
*period_coin_conds,
@@ -365,17 +382,23 @@ def dashboard_overview(
CoinTransaction.amount,
*period_coin_conds,
CoinTransaction.biz_type.in_(COUPON_REWARD_BIZ_TYPES),
)
) + period_coupon_feed_coin_total
period_comparison_reward_coin_total = _sum(
CoinTransaction.amount,
*period_coin_conds,
CoinTransaction.biz_type.in_(COMPARISON_REWARD_BIZ_TYPES),
)
) + period_comparison_feed_coin_total
period_regular_task_coin_total = _sum(
CoinTransaction.amount,
*period_coin_conds,
CoinTransaction.biz_type.notin_(REGULAR_TASK_EXCLUDED_BIZ_TYPES),
)
period_classified_coin_total = (
period_coupon_reward_coin_total
+ period_comparison_reward_coin_total
+ period_reward_video_coin_total
+ period_regular_task_coin_total
)
period_cps_orders = list(
db.execute(
select(CpsOrder).where(
@@ -413,6 +436,41 @@ def dashboard_overview(
else None
)
total_reward_video_coin_total = _sum(
CoinTransaction.amount,
CoinTransaction.amount > 0,
CoinTransaction.biz_type.in_(REWARD_VIDEO_BIZ_TYPES),
)
total_coupon_reward_coin_total = _sum(
CoinTransaction.amount,
CoinTransaction.amount > 0,
CoinTransaction.biz_type.in_(COUPON_REWARD_BIZ_TYPES),
) + _sum(
AdFeedRewardRecord.coin,
AdFeedRewardRecord.status == "granted",
AdFeedRewardRecord.feed_scene == "coupon",
)
total_comparison_reward_coin_total = _sum(
CoinTransaction.amount,
CoinTransaction.amount > 0,
CoinTransaction.biz_type.in_(COMPARISON_REWARD_BIZ_TYPES),
) + _sum(
AdFeedRewardRecord.coin,
AdFeedRewardRecord.status == "granted",
AdFeedRewardRecord.feed_scene == "comparison",
)
total_regular_task_coin_total = _sum(
CoinTransaction.amount,
CoinTransaction.amount > 0,
CoinTransaction.biz_type.notin_(REGULAR_TASK_EXCLUDED_BIZ_TYPES),
)
total_classified_coin_total = (
total_coupon_reward_coin_total
+ total_comparison_reward_coin_total
+ total_reward_video_coin_total
+ total_regular_task_coin_total
)
return {
"users": {
"total": _count(User),
@@ -423,12 +481,12 @@ def dashboard_overview(
"dau": today_dau(db),
},
"coins": {
# 累计发放金币(coin_transaction 里所有 amount>0 之和;负数是兑换/扣减不计)
"granted_total": _sum(CoinTransaction.amount, CoinTransaction.amount > 0),
# 累计发放金币按大盘 4 个展示分类加总;未分类/运营手动/邀请奖励不进入本指标。
"granted_total": total_classified_coin_total,
"reward_video_coin_total": _sum(
CoinTransaction.amount,
CoinTransaction.amount > 0,
CoinTransaction.biz_type.in_(("reward_video", "ad_reward")),
CoinTransaction.biz_type.in_(REWARD_VIDEO_BIZ_TYPES),
),
"reward_video_watch_count": _count(
AdRewardRecord,
@@ -456,6 +514,10 @@ def dashboard_overview(
CoinTransaction.biz_type == "signin_boost",
),
"signin_boost_watch_count": _count(SigninBoostRecord),
"task_coin_total": total_regular_task_coin_total,
"coupon_reward_coin_total": total_coupon_reward_coin_total,
"comparison_reward_coin_total": total_comparison_reward_coin_total,
"regular_task_coin_total": total_regular_task_coin_total,
},
"cash": {
"withdraw_success_cents": _sum(
@@ -492,7 +554,7 @@ def dashboard_overview(
"average_saved_cents": period_avg_saved_cents,
},
"coins": {
"granted_total": _sum(CoinTransaction.amount, *period_coin_conds),
"granted_total": period_classified_coin_total,
"reward_video_coin_total": period_reward_video_coin_total,
"feed_ad_coin_total": period_feed_ad_coin_total,
"signin_coin_total": period_signin_coin_total,