feat: 接入起卦后端流程并完善积分扣减链路
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.db import get_db
|
||||
from v1.points.repository import PointsRepository
|
||||
from v1.points.service import PointsService
|
||||
|
||||
|
||||
def get_points_service(session: AsyncSession = Depends(get_db)) -> PointsService:
|
||||
return PointsService(repository=PointsRepository(session))
|
||||
@@ -56,3 +56,14 @@ class PointsRepository:
|
||||
)
|
||||
self._session.add(entry)
|
||||
await self._session.flush()
|
||||
|
||||
async def get_user_points(self, *, user_id: UUID) -> UserPoints:
|
||||
insert_stmt = (
|
||||
insert(UserPoints)
|
||||
.values(user_id=user_id)
|
||||
.on_conflict_do_nothing(index_elements=[UserPoints.user_id])
|
||||
)
|
||||
await self._session.execute(insert_stmt)
|
||||
|
||||
stmt = select(UserPoints).where(UserPoints.user_id == user_id)
|
||||
return (await self._session.execute(stmt)).scalar_one()
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from core.auth.models import CurrentUser
|
||||
from v1.points.dependencies import get_points_service
|
||||
from v1.points.schemas import PointsBalanceResponse
|
||||
from v1.points.service import PointsService
|
||||
from v1.users.dependencies import get_current_user
|
||||
|
||||
router = APIRouter(prefix="/points", tags=["points"])
|
||||
|
||||
|
||||
@router.get("/balance", response_model=PointsBalanceResponse)
|
||||
async def get_points_balance(
|
||||
service: Annotated[PointsService, Depends(get_points_service)],
|
||||
current_user: Annotated[CurrentUser, Depends(get_current_user)],
|
||||
) -> PointsBalanceResponse:
|
||||
result = await service.get_points_balance(user_id=current_user.id)
|
||||
return PointsBalanceResponse(
|
||||
balance=result.balance,
|
||||
frozenBalance=result.frozen_balance,
|
||||
availableBalance=result.available_balance,
|
||||
runCost=result.run_cost,
|
||||
canRun=result.can_run,
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class PointsBalanceResponse(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True, serialize_by_alias=True)
|
||||
|
||||
balance: int = Field(ge=0)
|
||||
frozen_balance: int = Field(alias="frozenBalance", ge=0)
|
||||
available_balance: int = Field(alias="availableBalance", ge=0)
|
||||
run_cost: int = Field(alias="runCost", gt=0)
|
||||
can_run: bool = Field(alias="canRun")
|
||||
@@ -22,6 +22,15 @@ class RunChargeResult:
|
||||
event_id: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PointsBalanceResult:
|
||||
balance: int
|
||||
frozen_balance: int
|
||||
available_balance: int
|
||||
run_cost: int
|
||||
can_run: bool
|
||||
|
||||
|
||||
class PointsService:
|
||||
def __init__(self, repository: PointsRepository) -> None:
|
||||
self._repository = repository
|
||||
@@ -51,6 +60,23 @@ class PointsService:
|
||||
)
|
||||
return available
|
||||
|
||||
async def get_points_balance(
|
||||
self,
|
||||
*,
|
||||
user_id: UUID,
|
||||
) -> PointsBalanceResult:
|
||||
account = await self._repository.get_user_points(user_id=user_id)
|
||||
balance = int(account.balance)
|
||||
frozen_balance = int(account.frozen_balance)
|
||||
available = max(balance - frozen_balance, 0)
|
||||
return PointsBalanceResult(
|
||||
balance=balance,
|
||||
frozen_balance=frozen_balance,
|
||||
available_balance=available,
|
||||
run_cost=RUN_POINTS_COST,
|
||||
can_run=available >= RUN_POINTS_COST,
|
||||
)
|
||||
|
||||
async def consume_successful_run_points(
|
||||
self,
|
||||
*,
|
||||
|
||||
Reference in New Issue
Block a user