Files
meijiaka-zy/python-api/app/crud/point_batch.py
T
小鱼开发 51521fc0dd feat(payment): 微信支付 APIv2 + 积分充值 + SMS 短信 + 双 Token 认证
- 微信支付从 APIv3 降级为 APIv2(MD5/XML)
- 积分系统:充值下单、微信回调、消费冻结/结算/退款
- SMS B2M 短信验证码服务
- 双 Token 认证(Access 30min + Refresh 30days)
- SSE 单设备踢人
- 用户设备管理、积分账户模型
- Alembic 迁移脚本
2026-05-07 18:43:02 +08:00

129 lines
3.3 KiB
Python

"""
积分批次 CRUD
=============
核心操作:按过期时间升序查询批次、扣减剩余积分、冻结/解冻、过期扫描。
"""
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.crud.base import CRUDBase
from app.models.point_batch import PointBatch
class PointBatchCRUD(CRUDBase[PointBatch]):
"""积分批次数据访问对象"""
def __init__(self) -> None:
super().__init__(PointBatch)
async def get_by_user_id(
self, db: AsyncSession, *, user_id: str
) -> list[PointBatch]:
"""根据用户 ID 获取所有批次(按过期时间升序,FIFO)"""
result = await db.execute(
select(PointBatch)
.where(PointBatch.user_id == user_id)
.order_by(PointBatch.expired_at.asc())
)
return list(result.scalars().all())
async def get_available_batches(
self, db: AsyncSession, *, user_id: str
) -> list[PointBatch]:
"""
获取用户可用的批次(remaining + frozen > 0)。
按过期时间升序排列,用于 FIFO 扣减。
"""
result = await db.execute(
select(PointBatch)
.where(
PointBatch.user_id == user_id,
PointBatch.remaining + PointBatch.frozen > 0,
)
.order_by(PointBatch.expired_at.asc())
)
return list(result.scalars().all())
async def get_expired_batches(
self, db: AsyncSession, *, limit: int = 1000
) -> list[PointBatch]:
"""
获取已过期的批次(remaining > 0)。
用于定时任务扫描过期积分。
"""
from datetime import UTC, datetime
result = await db.execute(
select(PointBatch)
.where(
PointBatch.expired_at <= datetime.now(UTC),
PointBatch.remaining > 0,
)
.limit(limit)
)
return list(result.scalars().all())
async def deduct_from_batch(
self,
db: AsyncSession,
*,
batch_id: str,
points: int,
) -> PointBatch:
"""
从指定批次扣减剩余积分。
用于消费结算时真正扣减批次积分。
"""
batch = await self.get(db, id=batch_id)
batch.remaining -= points
await db.commit()
await db.refresh(batch)
return batch
async def freeze_in_batch(
self,
db: AsyncSession,
*,
batch_id: str,
points: int,
) -> PointBatch:
"""
在指定批次冻结积分。
remaining 减少,frozen 增加。
"""
batch = await self.get(db, id=batch_id)
batch.remaining -= points
batch.frozen += points
await db.commit()
await db.refresh(batch)
return batch
async def unfreeze_in_batch(
self,
db: AsyncSession,
*,
batch_id: str,
points: int,
) -> PointBatch:
"""
在指定批次解冻积分(返还)。
frozen 减少,remaining 增加。
"""
batch = await self.get(db, id=batch_id)
batch.frozen -= points
batch.remaining += points
await db.commit()
await db.refresh(batch)
return batch
# 导出实例
point_batch = PointBatchCRUD()