Files
shaguabijia-app-server/app/api/v1/order.py
T
no_gen_mu 4d821bec26 feat(invite): 发奖口径改为「比价并下单」+ 好友已比价状态(is_compared) + DEV 造数/重置接口
- 邀请发奖触发从「上报比价」改为「实际下单」(order.py + compare_record.py + repositories/invite.py)
- 好友列表返回 is_compared 已比价状态 (schemas/invite.py + repositories/invite.py)
- 新增 DEV 内部接口(生产 is_prod 一律 404):
  - POST/DELETE /invite/seed-fake 造/清虚拟好友(测在途、好友列表 UI)
  - POST /invite/dev-reset 把固定测试号打回出厂态(反复当新用户测发奖)
- fix(deploy): 每日兑换定时器锁北京时区 Asia/Shanghai (daily-exchange.service/.timer)

不含测试文件(tests/ 及 scripts/invite_reward_e2e.* 本地自用,不入库)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 17:13:50 +08:00

45 lines
2.0 KiB
Python

import logging
from fastapi import APIRouter
from app.api.deps import CurrentUser, DbSession
from app.repositories import invite as crud_invite
from app.repositories import savings as crud_savings
from app.schemas.order import OrderReportOut, OrderReportRequest
logger = logging.getLogger("shagua.order")
router = APIRouter(prefix="/api/v1/order", tags=["order"])
@router.post(
"/report",
response_model=OrderReportOut,
summary="上报归因订单(比价后5分钟内点链接 + 支付金额与比价价相差≤1元)",
)
def report_order(req: OrderReportRequest, user: CurrentUser, db: DbSession) -> OrderReportOut:
# 记账唯一真相表是 savings_record(source='compare')。
rec, duplicated = crud_savings.create_from_report(db, user.id, req)
# 邀请 v2 发奖:被邀请人【实际下单】(而非仅完成比价)才给邀请人发邀请奖励金(幂等,只发一次)。
# 触发点从"比价成功上报"挪到这里(冰:完成比价并实际下单才算成功)。仅首次真实上报触发,
# 重复上报(duplicated)跳过。best-effort:发奖异常不影响订单上报本身(rec 已 commit),只 log;
# try_reward_on_compare 自带 compare_reward_granted 幂等闸,漏发靠后续对账补。
if not duplicated:
try:
reward = crud_invite.try_reward_on_compare(db, user.id)
if reward.status == "granted":
logger.info(
"invite order reward granted inviter=%s invitee=%s cents=%s",
reward.inviter_user_id, user.id, reward.reward_cents,
)
except Exception as e: # noqa: BLE001 best-effort,发奖失败不阻塞订单上报
logger.warning("invite order reward failed invitee=%s: %s", user.id, e)
return OrderReportOut(
id=rec.id,
platform=rec.platform or req.platform,
pay_channel=rec.pay_channel or req.pay_channel,
compared_price_cents=rec.compared_price_cents or 0,
paid_amount_cents=rec.order_amount_cents,
duplicated=duplicated,
)