Files
shaguabijia-app-server/app/crud/task.py
T
OuYingJun1024 0722d7b0d5 feat: 福利钱包+签到+省钱战绩+激励广告发奖+微信提现 后端
- 福利钱包: 金币/现金余额、流水、兑换 (api/v1/wallet.py, crud/wallet.py, models/wallet.py, schemas/welfare.py)
- 每日签到: 连续天数 + 档位奖励 (api/v1/signin.py, crud/signin.py, models/signin.py)
- 任务系统: "打开消息提醒"等任务领奖 (api/v1/tasks.py, crud/task.py, models/task.py)
- 省钱战绩: 省钱汇总/战绩/店铺菜品 (api/v1/savings.py, crud/savings.py, models/savings.py)
- 激励广告发奖: 穿山甲服务端回调 + 发奖规则 + 限流 (api/v1/ad.py, core/pangle.py, core/rewards.py, core/ratelimit.py, crud/ad_reward.py, schemas/ad.py, docs/ad_reward_golive_checklist.md)
- 微信提现: 商家转账到零钱 V3 (core/wxpay.py); user 表加微信 openid/nickname/avatar
- DB 迁移: 8 个 alembic (welfare 表/cash_transaction/openid 唯一约束/savings 店铺菜品/savings_record/ad_reward/withdraw_order+openid/user 微信字段)
- 运维脚本: reconcile_withdraws(对账) + reset_signin/reset_welfare + sim_pangle_callback(模拟穿山甲回调)
- 测试: test_welfare / test_withdraw / test_ad_reward
- 配置: .env.example + config.py 新增福利/广告/微信支付项; main.py 挂 5 个新路由

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 17:38:08 +08:00

72 lines
1.9 KiB
Python

"""一次性任务 CRUD:列表状态 + 领奖。
领奖原子化:写 user_task(唯一约束防重复)+ 发金币,同一事务 commit。
"""
from __future__ import annotations
from dataclasses import dataclass
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.core.rewards import TASK_REWARDS
from app.crud import wallet as crud_wallet
from app.models.task import UserTask
class UnknownTaskError(Exception):
"""task_key 不在已知任务表里。"""
class AlreadyClaimedError(Exception):
"""该任务已经领过奖了。"""
@dataclass
class TaskState:
task_key: str
coin: int
claimed: bool
def list_tasks(db: Session, user_id: int) -> list[TaskState]:
"""返回所有已知一次性任务及其领取状态。"""
stmt = select(UserTask.task_key).where(UserTask.user_id == user_id)
claimed_keys = set(db.execute(stmt).scalars().all())
return [
TaskState(task_key=key, coin=coin, claimed=key in claimed_keys)
for key, coin in TASK_REWARDS.items()
]
def claim_task(db: Session, user_id: int, task_key: str) -> tuple[int, int]:
"""领取一次性任务奖励。返回 (发放金币, 领奖后余额)。
未知任务抛 UnknownTaskError;重复领取抛 AlreadyClaimedError。
"""
if task_key not in TASK_REWARDS:
raise UnknownTaskError
existing = db.execute(
select(UserTask).where(
UserTask.user_id == user_id, UserTask.task_key == task_key
)
).scalar_one_or_none()
if existing is not None:
raise AlreadyClaimedError
coin = TASK_REWARDS[task_key]
db.add(
UserTask(
user_id=user_id,
task_key=task_key,
status="completed",
coin_awarded=coin,
)
)
acc, _ = crud_wallet.grant_coins(
db, user_id, coin, biz_type=f"task_{task_key}", ref_id=task_key
)
db.commit()
return coin, acc.coin_balance