新增优惠券发放功能
This commit is contained in:
parent
02dcebd28e
commit
623a1f97c4
@ -9,7 +9,10 @@ from app.models.coupon import (
|
|||||||
CouponInfo,
|
CouponInfo,
|
||||||
UserCouponCreate,
|
UserCouponCreate,
|
||||||
UserCouponInfo,
|
UserCouponInfo,
|
||||||
CouponStatus
|
CouponStatus,
|
||||||
|
CouponIssueRecordDB,
|
||||||
|
CouponIssueRecordCreate,
|
||||||
|
CouponIssueRecordInfo
|
||||||
)
|
)
|
||||||
from app.models.database import get_db
|
from app.models.database import get_db
|
||||||
from app.api.deps import get_admin_user, get_current_user
|
from app.api.deps import get_admin_user, get_current_user
|
||||||
@ -101,20 +104,55 @@ async def issue_coupon(
|
|||||||
if not coupon:
|
if not coupon:
|
||||||
return error_response(code=404, message="优惠券不存在")
|
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):
|
for _ in range(user_coupon.count):
|
||||||
manager = CouponManager(coupon)
|
user_coupon_obj = manager.add_coupon(
|
||||||
manager.add_coupon(
|
|
||||||
user_id=user_coupon.user_id,
|
user_id=user_coupon.user_id,
|
||||||
coupon_id=coupon.id,
|
coupon_id=coupon.id,
|
||||||
count=user_coupon.count,
|
|
||||||
expire_time=user_coupon.expire_time
|
expire_time=user_coupon.expire_time
|
||||||
)
|
)
|
||||||
|
db.add(user_coupon_obj)
|
||||||
|
user_coupons.append(user_coupon_obj)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
db.commit()
|
db.commit()
|
||||||
|
db.refresh(issue_record)
|
||||||
|
|
||||||
return success_response(
|
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:
|
except Exception as e:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
@ -164,10 +202,71 @@ async def get_all_coupons(
|
|||||||
admin: UserDB = Depends(get_admin_user)
|
admin: UserDB = Depends(get_admin_user)
|
||||||
):
|
):
|
||||||
"""获取所有优惠券列表(管理员)"""
|
"""获取所有优惠券列表(管理员)"""
|
||||||
coupons = db.query(CouponDB).order_by(
|
query = db.query(CouponDB).order_by(
|
||||||
CouponDB.create_time.desc()
|
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()
|
).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(
|
return success_response(
|
||||||
data=[CouponInfo.model_validate(c) for c in coupons]
|
data={
|
||||||
|
"total": total,
|
||||||
|
"items": result
|
||||||
|
}
|
||||||
)
|
)
|
||||||
@ -1,47 +1,47 @@
|
|||||||
from sqlalchemy.orm import Session
|
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 app.models.user import UserDB
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
class CouponManager:
|
class CouponManager:
|
||||||
def __init__(self, db: Session):
|
def __init__(self, coupon: CouponDB = None):
|
||||||
self.db = db
|
self.coupon = coupon
|
||||||
|
|
||||||
# 发放优惠券
|
# 发放优惠券
|
||||||
def add_coupon(
|
def add_coupon(
|
||||||
self,
|
self,
|
||||||
user_id: int,
|
user_id: int,
|
||||||
coupon_id: int,
|
coupon_id: int,
|
||||||
count: int,
|
count: int = 1,
|
||||||
expire_time: datetime
|
expire_time: datetime = None
|
||||||
):
|
) -> UserCouponDB:
|
||||||
try:
|
"""
|
||||||
# 检查优惠券是否存在
|
为用户发放优惠券
|
||||||
coupon = self.db.query(CouponDB).filter(CouponDB.id == coupon_id).first()
|
|
||||||
if not coupon:
|
Args:
|
||||||
raise ValueError("优惠券不存在")
|
user_id: 用户ID
|
||||||
|
coupon_id: 优惠券ID
|
||||||
|
count: 发放数量
|
||||||
|
expire_time: 过期时间
|
||||||
|
|
||||||
# 检查用户是否存在
|
Returns:
|
||||||
user = self.db.query(UserDB).filter(UserDB.userid == user_id).first()
|
UserCouponDB: 创建的用户优惠券对象
|
||||||
if not user:
|
"""
|
||||||
raise ValueError("用户不存在")
|
# 使用传入的优惠券对象
|
||||||
|
coupon = self.coupon
|
||||||
for _ in range(count):
|
|
||||||
# 发放优惠券
|
# 发放优惠券
|
||||||
user_coupon = UserCouponDB(
|
user_coupon = UserCouponDB(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
coupon_id=coupon_id,
|
coupon_id=coupon_id,
|
||||||
coupon_name=coupon.name,
|
coupon_name=coupon.name,
|
||||||
coupon_amount=coupon.amount,
|
coupon_amount=coupon.amount,
|
||||||
coupon_type=coupon.coupon_type,
|
coupon_type=coupon.coupon_type,
|
||||||
expire_time=expire_time,
|
expire_time=expire_time,
|
||||||
)
|
)
|
||||||
self.db.add(user_coupon)
|
|
||||||
|
return user_coupon
|
||||||
self.db.commit()
|
|
||||||
except Exception as e:
|
|
||||||
self.db.rollback()
|
|
||||||
raise e
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from sqlalchemy.sql import func
|
|||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from .database import Base
|
from .database import Base
|
||||||
import enum
|
import enum
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
class CouponStatus(str, enum.Enum):
|
class CouponStatus(str, enum.Enum):
|
||||||
UNUSED = "UNUSED"
|
UNUSED = "UNUSED"
|
||||||
@ -41,6 +42,23 @@ class UserCouponDB(Base):
|
|||||||
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
update_time = Column(DateTime(timezone=True), onupdate=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 模型
|
# Pydantic 模型
|
||||||
class CouponCreate(BaseModel):
|
class CouponCreate(BaseModel):
|
||||||
name: str = Field(..., max_length=100)
|
name: str = Field(..., max_length=100)
|
||||||
@ -66,6 +84,7 @@ class UserCouponCreate(BaseModel):
|
|||||||
user_id: int
|
user_id: int
|
||||||
coupon_id: int
|
coupon_id: int
|
||||||
expire_time: datetime
|
expire_time: datetime
|
||||||
|
remark: Optional[str] = None
|
||||||
count: int = Field(..., gt=0, description="发放数量")
|
count: int = Field(..., gt=0, description="发放数量")
|
||||||
|
|
||||||
class UserCouponInfo(BaseModel):
|
class UserCouponInfo(BaseModel):
|
||||||
@ -80,5 +99,26 @@ class UserCouponInfo(BaseModel):
|
|||||||
status: CouponStatus
|
status: CouponStatus
|
||||||
create_time: datetime
|
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:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
BIN
jobs.sqlite
BIN
jobs.sqlite
Binary file not shown.
Loading…
Reference in New Issue
Block a user