diff --git a/app/api/routers/rbac_compute_pricing.py b/app/api/routers/rbac_compute_pricing.py index 0af898a..485ce15 100644 --- a/app/api/routers/rbac_compute_pricing.py +++ b/app/api/routers/rbac_compute_pricing.py @@ -1020,7 +1020,9 @@ async def transfer_from_personal( raise HTTPException(status_code=500, detail="个人算力账号未就绪") total_micro = amount_fen * MICRO_PER_FEN - # ★ 服务端严格校验个人可用余额(以平台账本为权威,引擎余额为参考) + # ★ 个人可转余额以引擎可用额度为权威(quota - used_quota,即个人实际可消费的算力)。 + # 平台账本 compute_personal_balance 仅记录「个人充值/企业转入」的累计,可能与引擎额度 + # 不一致(赠送/历史调整等),转账时同步扣减、不足扣到 0、不转负。 from ..infrastructure.models import User as _User from sqlalchemy import update as _sa_update user_row = await db.session.get(_User, user["id"]) @@ -1030,34 +1032,30 @@ async def transfer_from_personal( quota_micro = int(user_bal.get("quota", 0) or 0) used_micro = int(user_bal.get("used_quota", 0) or 0) available_micro = max(0, quota_micro - used_micro) - except Exception as exc: - raise HTTPException(status_code=502, detail=f"查询个人余额失败: {exc}") from exc - if ledger_balance < amount_fen: - raise HTTPException( - status_code=400, - detail=f"个人可转余额不足:账本可用 ¥{ledger_balance / 100:.2f},尝试转出 ¥{body.amount_yuan:.2f}", - ) + except Exception as exc: # noqa: BLE001 + raise HTTPException(status_code=502, detail="查询个人余额失败,请稍后重试") from exc if available_micro < total_micro: raise HTTPException( status_code=400, - detail=f"个人可用余额不足:可用 ¥{available_micro / 1000000:.2f},尝试转出 ¥{body.amount_yuan:.2f}", + detail=f"个人可用余额不足:可用 ¥{available_micro / 1000000:.2f},本次需转出 ¥{body.amount_yuan:.2f}", ) - # 先扣账本(幂等条件更新,防止并发超扣) - upd = await db.session.execute( - _sa_update(_User) - .where(_User.id == user["id"], _User.compute_personal_balance >= amount_fen) - .values(compute_personal_balance=_User.compute_personal_balance - amount_fen) - ) - if upd.rowcount == 0: - raise HTTPException(status_code=400, detail="个人可转余额不足(账本校验失败)") - + # 先扣引擎额度(引擎为权威),成功后再落库 try: await compute_client.adjust_user_quota(engine_user_id, total_micro, "subtract") - except Exception as exc: - raise HTTPException(status_code=400, detail=f"个人余额扣减失败: {exc}") from exc + except Exception as exc: # noqa: BLE001 + raise HTTPException(status_code=400, detail="个人余额扣减失败,请稍后重试") from exc await compute_client.sync_user_mirror(db, engine_user_id) + # 账本同步扣减(不足扣到 0,不转负) + new_ledger = max(0, ledger_balance - amount_fen) + if new_ledger != ledger_balance: + await db.session.execute( + _sa_update(_User) + .where(_User.id == user["id"]) + .values(compute_personal_balance=new_ledger) + ) + # 增加企业余额 company.compute_balance = (company.compute_balance or 0) + amount_fen