新增优惠券发放功能

This commit is contained in:
aaron 2025-04-06 20:20:43 +08:00
parent 02dcebd28e
commit 623a1f97c4
4 changed files with 178 additions and 39 deletions

View File

@ -9,7 +9,10 @@ from app.models.coupon import (
CouponInfo,
UserCouponCreate,
UserCouponInfo,
CouponStatus
CouponStatus,
CouponIssueRecordDB,
CouponIssueRecordCreate,
CouponIssueRecordInfo
)
from app.models.database import get_db
from app.api.deps import get_admin_user, get_current_user
@ -101,20 +104,55 @@ async def issue_coupon(
if not coupon:
return error_response(code=404, message="优惠券不存在")
# 查询用户信息
user = db.query(UserDB).filter(UserDB.userid == user_coupon.user_id).first()
if not user:
return error_response(code=404, message="用户不存在")
# 创建发放记录
issue_record = CouponIssueRecordDB(
coupon_id=coupon.id,
user_id=user_coupon.user_id,
operator_id=admin.userid,
count=user_coupon.count,
remark=f"{admin.nickname}: {user_coupon.remark}" if user_coupon.remark else f"{admin.nickname} 手动发放"
)
db.add(issue_record)
# 批量创建用户优惠券
manager = CouponManager(coupon)
user_coupons = []
for _ in range(user_coupon.count):
manager = CouponManager(coupon)
manager.add_coupon(
user_coupon_obj = manager.add_coupon(
user_id=user_coupon.user_id,
coupon_id=coupon.id,
count=user_coupon.count,
expire_time=user_coupon.expire_time
)
db.add(user_coupon_obj)
user_coupons.append(user_coupon_obj)
try:
db.commit()
db.refresh(issue_record)
return success_response(
message=f"成功发放 {user_coupon.count} 张优惠券"
message=f"成功发放 {user_coupon.count} 张优惠券",
data={
"issue_record": CouponIssueRecordInfo(
id=issue_record.id,
coupon_id=issue_record.coupon_id,
user_id=issue_record.user_id,
operator_id=issue_record.operator_id,
count=issue_record.count,
issue_time=issue_record.issue_time,
remark=issue_record.remark,
coupon_name=coupon.name,
user_nickname=user.nickname,
operator_nickname=admin.nickname
),
"coupon_count": len(user_coupons)
}
)
except Exception as e:
db.rollback()
@ -164,10 +202,71 @@ async def get_all_coupons(
admin: UserDB = Depends(get_admin_user)
):
"""获取所有优惠券列表(管理员)"""
coupons = db.query(CouponDB).order_by(
query = db.query(CouponDB).order_by(
CouponDB.create_time.desc()
)
total = query.count()
items = query.offset(skip).limit(limit).all()
return success_response(
data={
"total": total,
"items": [CouponInfo.model_validate(c) for c in items]
}
)
@router.get("/issue/records", response_model=ResponseModel)
async def get_issue_records(
skip: int = 0,
limit: int = 10,
coupon_id: Optional[int] = None,
user_id: Optional[int] = None,
db: Session = Depends(get_db),
admin: UserDB = Depends(get_admin_user)
):
"""获取优惠券发放记录(管理员)"""
query = db.query(CouponIssueRecordDB)
# 添加过滤条件
if coupon_id:
query = query.filter(CouponIssueRecordDB.coupon_id == coupon_id)
if user_id:
query = query.filter(CouponIssueRecordDB.user_id == user_id)
# 计算总数
total = query.count()
# 获取数据
records = query.order_by(
CouponIssueRecordDB.issue_time.desc()
).offset(skip).limit(limit).all()
# 构建响应数据
result = []
for record in records:
# 获取关联信息
coupon = db.query(CouponDB).filter(CouponDB.id == record.coupon_id).first()
user = db.query(UserDB).filter(UserDB.userid == record.user_id).first()
operator = db.query(UserDB).filter(UserDB.userid == record.operator_id).first()
record_info = CouponIssueRecordInfo(
id=record.id,
coupon_id=record.coupon_id,
user_id=record.user_id,
operator_id=record.operator_id,
count=record.count,
issue_time=record.issue_time,
remark=record.remark,
coupon_name=coupon.name if coupon else None,
user_nickname=user.nickname if user else None,
operator_nickname=operator.nickname if operator else None
)
result.append(record_info)
return success_response(
data=[CouponInfo.model_validate(c) for c in coupons]
data={
"total": total,
"items": result
}
)

View File

@ -1,47 +1,47 @@
from sqlalchemy.orm import Session
from app.models.coupon import CouponDB,UserCouponDB
from app.models.coupon import CouponDB, UserCouponDB
from app.models.user import UserDB
from datetime import datetime
from typing import Optional, List
class CouponManager:
def __init__(self, db: Session):
self.db = db
def __init__(self, coupon: CouponDB = None):
self.coupon = coupon
# 发放优惠券
def add_coupon(
self,
user_id: int,
coupon_id: int,
count: int,
expire_time: datetime
):
try:
# 检查优惠券是否存在
coupon = self.db.query(CouponDB).filter(CouponDB.id == coupon_id).first()
if not coupon:
raise ValueError("优惠券不存在")
count: int = 1,
expire_time: datetime = None
) -> UserCouponDB:
"""
为用户发放优惠券
Args:
user_id: 用户ID
coupon_id: 优惠券ID
count: 发放数量
expire_time: 过期时间
# 检查用户是否存在
user = self.db.query(UserDB).filter(UserDB.userid == user_id).first()
if not user:
raise ValueError("用户不存在")
for _ in range(count):
# 发放优惠券
user_coupon = UserCouponDB(
user_id=user_id,
coupon_id=coupon_id,
coupon_name=coupon.name,
coupon_amount=coupon.amount,
coupon_type=coupon.coupon_type,
expire_time=expire_time,
)
self.db.add(user_coupon)
self.db.commit()
except Exception as e:
self.db.rollback()
raise e
Returns:
UserCouponDB: 创建的用户优惠券对象
"""
# 使用传入的优惠券对象
coupon = self.coupon
# 发放优惠券
user_coupon = UserCouponDB(
user_id=user_id,
coupon_id=coupon_id,
coupon_name=coupon.name,
coupon_amount=coupon.amount,
coupon_type=coupon.coupon_type,
expire_time=expire_time,
)
return user_coupon

View File

@ -5,6 +5,7 @@ from sqlalchemy.sql import func
from pydantic import BaseModel, Field
from .database import Base
import enum
from sqlalchemy.orm import relationship
class CouponStatus(str, enum.Enum):
UNUSED = "UNUSED"
@ -41,6 +42,23 @@ class UserCouponDB(Base):
create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now())
class CouponIssueRecordDB(Base):
"""优惠券发放记录表"""
__tablename__ = "coupon_issue_records"
id = Column(Integer, primary_key=True, autoincrement=True)
coupon_id = Column(Integer, ForeignKey("coupons.id"), nullable=False)
user_id = Column(Integer, ForeignKey("users.userid"), nullable=False)
operator_id = Column(Integer, ForeignKey("users.userid"), nullable=False) # 操作人ID
count = Column(Integer, nullable=False, default=1) # 发放数量
issue_time = Column(DateTime(timezone=True), nullable=False, server_default=func.now())
remark = Column(String(200), nullable=True) # 备注信息
# 关联关系
coupon = relationship("CouponDB", backref="issue_records")
user = relationship("UserDB", foreign_keys=[user_id], backref="received_coupon_records")
operator = relationship("UserDB", foreign_keys=[operator_id], backref="operated_coupon_records")
# Pydantic 模型
class CouponCreate(BaseModel):
name: str = Field(..., max_length=100)
@ -66,6 +84,7 @@ class UserCouponCreate(BaseModel):
user_id: int
coupon_id: int
expire_time: datetime
remark: Optional[str] = None
count: int = Field(..., gt=0, description="发放数量")
class UserCouponInfo(BaseModel):
@ -80,5 +99,26 @@ class UserCouponInfo(BaseModel):
status: CouponStatus
create_time: datetime
class Config:
from_attributes = True
class CouponIssueRecordCreate(BaseModel):
coupon_id: int
user_id: int
count: int = 1
remark: Optional[str] = None
class CouponIssueRecordInfo(BaseModel):
id: int
coupon_id: int
user_id: int
operator_id: int
count: int
issue_time: datetime
remark: Optional[str] = None
coupon_name: Optional[str] = None
user_nickname: Optional[str] = None
operator_nickname: Optional[str] = None
class Config:
from_attributes = True

Binary file not shown.