67a9a15775
- 新增 app_config 表 + model/repository/config_schema + admin config 路由与 schema + 测试 - rewards.py 及 ad_reward/signin/task/wallet/comparison_milestone repositories 接入可配置项;ad.py / admin/main.py 配套 - alembic merge(ebb6af5c0b56)合并本地 app_config(cfg1a2b3c4d5)与 incoming price_report/best_deeplink(b7e2c1a9f4d3)两 head Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Reviewed-on: #14
115 lines
3.8 KiB
Python
115 lines
3.8 KiB
Python
"""比价战绩里程碑 CRUD:进度查询 + 逐档领奖。
|
|
|
|
进度 = comparison_record 里 status='success' 的条数(crud_compare.count_success)。
|
|
第 N 档在"成功次数 >= N"时解锁;每档领一次,写 comparison_milestone_claim 去重(标记已领)。
|
|
档位金额来自 rewards.get_record_milestones(运营后台可改)。
|
|
⚠️ 当前产品定暂不真发金币(后续整体删除该功能):claim 只写领取记录,不调 grant_coins、
|
|
不写 coin_transaction,coin_awarded 恒为 0,余额不变。仿一次性任务 (task.py)。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core import rewards
|
|
from app.models.comparison_milestone import ComparisonMilestoneClaim
|
|
from app.repositories import comparison as crud_compare
|
|
from app.repositories import wallet as crud_wallet
|
|
|
|
|
|
class UnknownMilestoneError(Exception):
|
|
"""档位序号越界(不在 1..档位数)。"""
|
|
|
|
|
|
class MilestoneLockedError(Exception):
|
|
"""该档还没解锁(成功比价次数不够)。"""
|
|
|
|
|
|
class AlreadyClaimedError(Exception):
|
|
"""该档已经领过了。"""
|
|
|
|
|
|
@dataclass
|
|
class MilestoneState:
|
|
milestone: int # 1-based 档位序号
|
|
coin: int
|
|
state: str # claimed / active / locked
|
|
|
|
|
|
@dataclass
|
|
class MilestoneStatus:
|
|
success_count: int # 累计成功比价次数(解锁进度)
|
|
claimable_count: int # 当前可领(active)档数
|
|
milestones: list[MilestoneState]
|
|
|
|
|
|
def _claimed_set(db: Session, user_id: int) -> set[int]:
|
|
rows = db.execute(
|
|
select(ComparisonMilestoneClaim.milestone).where(
|
|
ComparisonMilestoneClaim.user_id == user_id
|
|
)
|
|
).scalars().all()
|
|
return set(rows)
|
|
|
|
|
|
def get_status(db: Session, user_id: int) -> MilestoneStatus:
|
|
"""各档领取状态:已领=claimed,已解锁未领=active(可领),未解锁=locked。"""
|
|
success_count = crud_compare.count_success(db, user_id)
|
|
claimed = _claimed_set(db, user_id)
|
|
milestones_def = rewards.get_record_milestones(db)
|
|
|
|
milestones: list[MilestoneState] = []
|
|
claimable = 0
|
|
for m in range(1, len(milestones_def) + 1):
|
|
if m in claimed:
|
|
state = "claimed"
|
|
elif success_count >= m:
|
|
state = "active"
|
|
claimable += 1
|
|
else:
|
|
state = "locked"
|
|
milestones.append(
|
|
MilestoneState(milestone=m, coin=milestones_def[m - 1], state=state)
|
|
)
|
|
|
|
return MilestoneStatus(
|
|
success_count=success_count,
|
|
claimable_count=claimable,
|
|
milestones=milestones,
|
|
)
|
|
|
|
|
|
def claim(db: Session, user_id: int, milestone: int) -> tuple[int, int]:
|
|
"""领取第 milestone 档奖励。返回 (发放金币, 领奖后余额)。
|
|
|
|
越界抛 UnknownMilestoneError;未解锁抛 MilestoneLockedError;重复领抛 AlreadyClaimedError。
|
|
"""
|
|
if milestone < 1 or milestone > len(rewards.get_record_milestones(db)):
|
|
raise UnknownMilestoneError
|
|
|
|
existing = db.execute(
|
|
select(ComparisonMilestoneClaim).where(
|
|
ComparisonMilestoneClaim.user_id == user_id,
|
|
ComparisonMilestoneClaim.milestone == milestone,
|
|
)
|
|
).scalar_one_or_none()
|
|
if existing is not None:
|
|
raise AlreadyClaimedError
|
|
|
|
# 解锁校验:成功比价次数必须 >= 档位序号
|
|
if crud_compare.count_success(db, user_id) < milestone:
|
|
raise MilestoneLockedError
|
|
|
|
# ⚠️ 比价战绩里程碑暂不真发金币(产品定,后续整体删除该功能):仍记一条领取(去重/标记已领),
|
|
# 但不调 grant_coins、不写 coin_transaction,余额不变,返回发放 0 金币 + 当前余额。
|
|
db.add(
|
|
ComparisonMilestoneClaim(
|
|
user_id=user_id, milestone=milestone, coin_awarded=0
|
|
)
|
|
)
|
|
acc = crud_wallet.get_or_create_account(db, user_id, commit=False)
|
|
db.commit()
|
|
return 0, acc.coin_balance
|