添加授权依赖
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""功能权限 Service
|
||||
|
||||
校验用户功能权限并扣减库存,业务异常时回退。
|
||||
逻辑与 Java 端 FuncPermissionService 完全一致。
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import select, func, update, delete
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.func_permission import FuncPermission
|
||||
from app.models.user_func_permission_stock import UserFuncPermissionStock
|
||||
from app.models.user_func_usage_log import UserFuncUsageLog
|
||||
|
||||
|
||||
class FuncPermissionService:
|
||||
|
||||
def __init__(self, session: AsyncSession):
|
||||
self.session = session
|
||||
|
||||
async def check_and_deduct(self, user_id: int, func_code: str) -> int:
|
||||
"""校验权限 + 扣减库存,返回使用记录ID"""
|
||||
|
||||
# 1. 查功能权限定义
|
||||
result = await self.session.execute(select(FuncPermission).where(FuncPermission.func_code == func_code, FuncPermission.status == 1, FuncPermission.is_delete == 0))
|
||||
perm = result.scalar_one_or_none()
|
||||
|
||||
if perm is None:
|
||||
raise HTTPException(status_code=403, detail="功能不存在或未启用")
|
||||
|
||||
# 2. 判断每日免费额度
|
||||
daily_free = perm.daily_free_count or 0
|
||||
if daily_free > 0:
|
||||
today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
result = await self.session.execute(select(func.count()).select_from(UserFuncUsageLog).where(UserFuncUsageLog.user_id == user_id, UserFuncUsageLog.func_code == func_code, UserFuncUsageLog.create_time >= today_start,))
|
||||
today_used = result.scalar() or 0
|
||||
|
||||
if today_used < daily_free:
|
||||
return await self._insert_usage_log(user_id, func_code)
|
||||
|
||||
# 3. 查付费库存
|
||||
result = await self.session.execute(select(UserFuncPermissionStock).where(UserFuncPermissionStock.user_id == user_id, UserFuncPermissionStock.func_code == func_code))
|
||||
stock = result.scalar_one_or_none()
|
||||
if stock is None:
|
||||
raise HTTPException(status_code=403, detail="无该功能权限")
|
||||
|
||||
# 4. 时间维度校验
|
||||
if stock.time_limit == 1 and stock.expire_time is not None:
|
||||
if stock.expire_time < datetime.now():
|
||||
raise HTTPException(status_code=403, detail="功能权限已过期")
|
||||
|
||||
# 5. 次数维度校验
|
||||
if stock.count_limit == 0:
|
||||
return await self._insert_usage_log(user_id, func_code)
|
||||
|
||||
# 限次,SQL 原子扣减
|
||||
result = await self.session.execute(update(UserFuncPermissionStock).where(UserFuncPermissionStock.user_id == user_id, UserFuncPermissionStock.func_code == func_code, UserFuncPermissionStock.remain_count > 0).values(remain_count=UserFuncPermissionStock.remain_count - 1))
|
||||
|
||||
if result.rowcount == 0:
|
||||
raise HTTPException(status_code=403, detail="功能使用次数已用完")
|
||||
|
||||
return await self._insert_usage_log(user_id, func_code)
|
||||
|
||||
async def rollback_usage(self, log_id: int, user_id: int, func_code: str) -> None:
|
||||
"""回退使用记录 + 库存"""
|
||||
# 删除使用记录
|
||||
await self.session.execute(delete(UserFuncUsageLog).where(UserFuncUsageLog.id == log_id))
|
||||
|
||||
# 尝试回退库存(count_limit=1 才会匹配)
|
||||
await self.session.execute(update(UserFuncPermissionStock).where(UserFuncPermissionStock.user_id == user_id, UserFuncPermissionStock.func_code == func_code, UserFuncPermissionStock.count_limit == 1).values(remain_count=UserFuncPermissionStock.remain_count + 1))
|
||||
|
||||
async def _insert_usage_log(self, user_id: int, func_code: str) -> int:
|
||||
"""插入使用记录,返回记录ID"""
|
||||
usage_log = UserFuncUsageLog(user_id=user_id, func_code=func_code)
|
||||
self.session.add(usage_log)
|
||||
await self.session.flush()
|
||||
return usage_log.id
|
||||
Reference in New Issue
Block a user