Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 04154b38bd |
@@ -788,6 +788,7 @@ def get_user_overview(db: Session, user_id: int) -> dict | None:
|
|||||||
"user": user,
|
"user": user,
|
||||||
"coin_balance": acc.coin_balance if acc else 0,
|
"coin_balance": acc.coin_balance if acc else 0,
|
||||||
"cash_balance_cents": acc.cash_balance_cents if acc else 0,
|
"cash_balance_cents": acc.cash_balance_cents if acc else 0,
|
||||||
|
"invite_cash_balance_cents": acc.invite_cash_balance_cents if acc else 0,
|
||||||
"total_coin_earned": acc.total_coin_earned if acc else 0,
|
"total_coin_earned": acc.total_coin_earned if acc else 0,
|
||||||
"comparison_total": _count(ComparisonRecord, ComparisonRecord.user_id == user_id),
|
"comparison_total": _count(ComparisonRecord, ComparisonRecord.user_id == user_id),
|
||||||
"comparison_success": _count(
|
"comparison_success": _count(
|
||||||
|
|||||||
+19
-11
@@ -210,22 +210,28 @@ def grant_user_cash(
|
|||||||
db: AdminDb,
|
db: AdminDb,
|
||||||
) -> OkResponse:
|
) -> OkResponse:
|
||||||
"""给指定用户增/减或设值现金(分)。delta:正=发放、负=扣减;set:直接设为目标值。
|
"""给指定用户增/减或设值现金(分)。delta:正=发放、负=扣减;set:直接设为目标值。
|
||||||
|
account=coin_cash(金币兑现金)/ invite_cash(邀请奖励金):两本账物理隔离、各调各的。
|
||||||
主要用于让无现金用户直接测试提现。"""
|
主要用于让无现金用户直接测试提现。"""
|
||||||
user = user_repo.get_user_by_id(db, user_id)
|
user = user_repo.get_user_by_id(db, user_id)
|
||||||
if user is None:
|
if user is None:
|
||||||
raise HTTPException(status_code=404, detail="用户不存在")
|
raise HTTPException(status_code=404, detail="用户不存在")
|
||||||
# set=设为目标值:读当前余额算差值,仍复用 grant_cash 写一笔流水(沿用原子/审计/扣负保护)
|
# 按目标账户选「余额字段 + 变动入口」(grant_invite_cash 与 grant_cash 同构)
|
||||||
|
is_invite = body.account == "invite_cash"
|
||||||
|
balance_attr = "invite_cash_balance_cents" if is_invite else "cash_balance_cents"
|
||||||
|
grant_fn = wallet_repo.grant_invite_cash if is_invite else wallet_repo.grant_cash
|
||||||
|
acct_label = "邀请奖励金" if is_invite else "现金"
|
||||||
|
before: int | None = None
|
||||||
|
# set=设为目标值:读当前余额算差值,仍复用 grant 写一笔流水(沿用原子/审计/扣负保护)
|
||||||
if body.mode == "set":
|
if body.mode == "set":
|
||||||
if body.amount_cents < 0:
|
if body.amount_cents < 0:
|
||||||
raise HTTPException(status_code=400, detail="目标现金值不能为负")
|
raise HTTPException(status_code=400, detail=f"目标{acct_label}值不能为负")
|
||||||
# lock=True:锁账户行,防连点/并发各读同一 before 算同一 delta 双写,余额错位
|
# lock=True:锁账户行,防连点/并发各读同一 before 算同一 delta 双写,余额错位
|
||||||
before = wallet_repo.get_or_create_account(
|
acc_locked = wallet_repo.get_or_create_account(db, user_id, commit=False, lock=True)
|
||||||
db, user_id, commit=False, lock=True
|
before = getattr(acc_locked, balance_attr)
|
||||||
).cash_balance_cents
|
|
||||||
delta = body.amount_cents - before
|
delta = body.amount_cents - before
|
||||||
if delta == 0:
|
if delta == 0:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=400, detail=f"当前现金已为 {body.amount_cents} 分,无需调整"
|
status_code=400, detail=f"当前{acct_label}已为 {body.amount_cents} 分,无需调整"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if body.amount_cents == 0:
|
if body.amount_cents == 0:
|
||||||
@@ -234,18 +240,20 @@ def grant_user_cash(
|
|||||||
# 负数扣减时不允许扣成负余额(运营误操作保护);lock=True 防并发扣穿
|
# 负数扣减时不允许扣成负余额(运营误操作保护);lock=True 防并发扣穿
|
||||||
if delta < 0:
|
if delta < 0:
|
||||||
acc_now = wallet_repo.get_or_create_account(db, user_id, commit=False, lock=True)
|
acc_now = wallet_repo.get_or_create_account(db, user_id, commit=False, lock=True)
|
||||||
if acc_now.cash_balance_cents + delta < 0:
|
if getattr(acc_now, balance_attr) + delta < 0:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=400, detail=f"扣减后现金为负(当前余额 {acc_now.cash_balance_cents} 分)"
|
status_code=400,
|
||||||
|
detail=f"扣减后{acct_label}为负(当前余额 {getattr(acc_now, balance_attr)} 分)",
|
||||||
)
|
)
|
||||||
biz_type = "admin_grant" if delta > 0 else "admin_deduct"
|
biz_type = "admin_grant" if delta > 0 else "admin_deduct"
|
||||||
# grant_cash 只 flush 不 commit;审计同 commit=False;最后一起 commit → 原子(改钱+留痕)
|
# grant 只 flush 不 commit;审计同 commit=False;最后一起 commit → 原子(改钱+留痕)
|
||||||
acc, _ = wallet_repo.grant_cash(
|
acc, _ = grant_fn(
|
||||||
db, user_id, delta, biz_type=biz_type, remark=f"admin:{body.reason}"[:128],
|
db, user_id, delta, biz_type=biz_type, remark=f"admin:{body.reason}"[:128],
|
||||||
)
|
)
|
||||||
detail = {
|
detail = {
|
||||||
|
"account": body.account,
|
||||||
"amount_cents": delta,
|
"amount_cents": delta,
|
||||||
"balance_after_cents": acc.cash_balance_cents,
|
"balance_after_cents": getattr(acc, balance_attr),
|
||||||
"reason": body.reason,
|
"reason": body.reason,
|
||||||
}
|
}
|
||||||
if body.mode == "set":
|
if body.mode == "set":
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class AdminUserOverview(BaseModel):
|
|||||||
user: AdminUserListItem
|
user: AdminUserListItem
|
||||||
coin_balance: int
|
coin_balance: int
|
||||||
cash_balance_cents: int
|
cash_balance_cents: int
|
||||||
|
invite_cash_balance_cents: int # 邀请奖励金余额(与 cash_balance_cents 物理隔离)
|
||||||
total_coin_earned: int
|
total_coin_earned: int
|
||||||
comparison_total: int
|
comparison_total: int
|
||||||
comparison_success: int
|
comparison_success: int
|
||||||
@@ -88,6 +89,11 @@ class GrantCoinsRequest(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class GrantCashRequest(BaseModel):
|
class GrantCashRequest(BaseModel):
|
||||||
|
# 目标账户:金币兑换的现金(cash_balance_cents)与邀请奖励金(invite_cash_balance_cents)物理隔离,
|
||||||
|
# 各调各的、不可串。默认 coin_cash 兼容旧调用。
|
||||||
|
account: Literal["coin_cash", "invite_cash"] = Field(
|
||||||
|
"coin_cash", description="目标账户:coin_cash=金币兑现金账户 / invite_cash=邀请奖励金账户"
|
||||||
|
)
|
||||||
mode: Literal["delta", "set"] = Field(
|
mode: Literal["delta", "set"] = Field(
|
||||||
"delta", description="delta=增减(amount_cents 为变动量) / set=设为(amount_cents 为目标值,须≥0)"
|
"delta", description="delta=增减(amount_cents 为变动量) / set=设为(amount_cents 为目标值,须≥0)"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user