coupon 增加类型 和 核销功能。

This commit is contained in:
aaron 2025-02-25 12:40:43 +08:00
parent 0d2e503965
commit c0ec42ca8a
5 changed files with 76 additions and 16 deletions

View File

@ -37,6 +37,33 @@ async def create_coupon(
db.rollback() db.rollback()
return error_response(code=500, message=f"创建优惠券失败: {str(e)}") return error_response(code=500, message=f"创建优惠券失败: {str(e)}")
@router.put("/{coupon_id}/beused", response_model=ResponseModel)
async def beused_coupon(
coupon_id: int,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
""" 使用优惠券 """
coupon = db.query(UserCouponDB).filter(
UserCouponDB.id == coupon_id,
UserCouponDB.user_id == current_user.userid,
UserCouponDB.status == CouponStatus.UNUSED,
UserCouponDB.expire_time > datetime.now()
).first()
if not coupon:
return error_response(code=404, message="优惠券不存在")
coupon.status = CouponStatus.USED
coupon.used_time = datetime.now()
db.commit()
return success_response(data=CouponInfo.model_validate(coupon))
@router.put("/{coupon_id}", response_model=ResponseModel) @router.put("/{coupon_id}", response_model=ResponseModel)
async def update_coupon( async def update_coupon(
coupon_id: int, coupon_id: int,

View File

@ -19,7 +19,7 @@ from app.models.database import get_db
from app.api.deps import get_current_user, get_deliveryman_user, get_admin_user from app.api.deps import get_current_user, get_deliveryman_user, get_admin_user
from app.models.user import UserDB,UserRole from app.models.user import UserDB,UserRole
from app.core.response import success_response, error_response, ResponseModel from app.core.response import success_response, error_response, ResponseModel
from app.models.coupon import UserCouponDB, CouponStatus from app.models.coupon import UserCouponDB, CouponStatus, CouponType
from app.models.point_product_order import PointProductOrderDB, PointProductOrderInfo, PointProductOrderStatus from app.models.point_product_order import PointProductOrderDB, PointProductOrderInfo, PointProductOrderStatus
from datetime import datetime, timezone from datetime import datetime, timezone
from app.core.config import settings from app.core.config import settings
@ -115,6 +115,7 @@ def calculate_price(price_request: OrderPriceCalculateRequest,user: UserDB,db: S
# 1. 查找用户可用的优惠券(按金额从大到小排序) # 1. 查找用户可用的优惠券(按金额从大到小排序)
available_coupon = db.query(UserCouponDB).filter( available_coupon = db.query(UserCouponDB).filter(
UserCouponDB.user_id == user.userid, UserCouponDB.user_id == user.userid,
UserCouponDB.coupon_type == CouponType.CASH,
UserCouponDB.status == CouponStatus.UNUSED, UserCouponDB.status == CouponStatus.UNUSED,
UserCouponDB.expire_time > datetime.now() UserCouponDB.expire_time > datetime.now()
).order_by(UserCouponDB.coupon_amount.desc()).first() ).order_by(UserCouponDB.coupon_amount.desc()).first()
@ -192,7 +193,7 @@ async def create_order(
# 查询用户优惠券 # 查询用户优惠券
if coupon_id: if coupon_id:
user_coupon = db.query(UserCouponDB).filter( user_coupon = db.query(UserCouponDB).filter(
UserCouponDB.id == coupon_id UserCouponDB.id == coupon_id,
).first() ).first()
if user_coupon: if user_coupon:
@ -268,6 +269,7 @@ async def create_order(
).first() ).first()
if coupon: if coupon:
coupon.status = CouponStatus.USED coupon.status = CouponStatus.USED
coupon.used_time = datetime.now()
# 如果使用了积分,扣减用户积分并记录 # 如果使用了积分,扣减用户积分并记录
if price_result.used_points: if price_result.used_points:
@ -672,6 +674,7 @@ async def cancel_order(
).first() ).first()
if coupon: if coupon:
coupon.status = CouponStatus.UNUSED coupon.status = CouponStatus.UNUSED
coupon.used_time = None
# 检查子订单是否全部取消 # 检查子订单是否全部取消
sub_orders = db.query(PointProductOrderDB).filter( sub_orders = db.query(PointProductOrderDB).filter(
@ -877,6 +880,7 @@ async def deliveryman_cancel_order(
).first() ).first()
if coupon: if coupon:
coupon.status = CouponStatus.UNUSED coupon.status = CouponStatus.UNUSED
coupon.used_time = None
# 检查子订单是否全部取消 # 检查子订单是否全部取消
sub_orders = db.query(PointProductOrderDB).filter( sub_orders = db.query(PointProductOrderDB).filter(

View File

@ -24,6 +24,8 @@ from app.core.qcloud import qcloud_manager
from app.models.merchant import MerchantDB from app.models.merchant import MerchantDB
from app.models.address import AddressDB, AddressInfo from app.models.address import AddressDB, AddressInfo
from app.models.user import UserUpdateRoles, UserUpdateDeliveryCommissionRate from app.models.user import UserUpdateRoles, UserUpdateDeliveryCommissionRate
from app.models.order import ShippingOrderDB
router = APIRouter() router = APIRouter()
# Redis 连接 # Redis 连接
@ -343,6 +345,8 @@ async def password_login(
@router.get("/referrals", response_model=ResponseModel) @router.get("/referrals", response_model=ResponseModel)
async def get_referral_users( async def get_referral_users(
skip: int = 0,
limit: int = 10,
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user) current_user: UserDB = Depends(get_current_user)
): ):
@ -351,19 +355,30 @@ async def get_referral_users(
UserDB.referral_code == current_user.user_code UserDB.referral_code == current_user.user_code
).order_by( ).order_by(
UserDB.create_time.desc() UserDB.create_time.desc()
).all() ).offset(skip).limit(limit).all()
# 处理手机号脱敏 total = db.query(UserDB).filter(
def mask_phone(phone: str) -> str: UserDB.referral_code == current_user.user_code
return f"{phone[:3]}****{phone[7:]}" ).count()
return success_response(data=[ user_list = []
ReferralUserInfo(
nickname=user.nickname, # 获取用户是否下单
phone=mask_phone(user.phone), for user in referral_users:
create_time=user.create_time u = ReferralUserInfo.model_validate(user).model_dump()
) for user in referral_users
]) order_count = db.query(ShippingOrderDB).filter(
ShippingOrderDB.userid == user.userid
).count()
u['is_place_order'] = order_count > 0
u['phone'] = f"{u['phone'][:3]}****{u['phone'][7:]}"
user_list.append(u)
return success_response(data={
"total": total,
"items": user_list
})
def issue_register_coupons(db: Session, user_id: int): def issue_register_coupons(db: Session, user_id: int):
"""发放注册优惠券 """发放注册优惠券

View File

@ -85,7 +85,6 @@ async def exception_handler(request, exc):
**请求信息** **请求信息**
> 请求方法{request.method} > 请求方法{request.method}
> 请求URL{request.url} > 请求URL{request.url}
> 请求头{request.headers}
> 请求体{request.body} > 请求体{request.body}
**异常信息** **异常信息**
@ -96,5 +95,8 @@ async def exception_handler(request, exc):
return CustomJSONResponse( return CustomJSONResponse(
status_code=500, status_code=500,
content=str(exc) content={
"code": 500,
"message": str(exc)
}
) )

View File

@ -11,6 +11,10 @@ class CouponStatus(str, enum.Enum):
USED = "USED" USED = "USED"
EXPIRED = "EXPIRED" EXPIRED = "EXPIRED"
class CouponType(str, enum.Enum):
PRODUCT = "PRODUCT" # 商品
CASH = "CASH" # 现金
# 数据库模型 # 数据库模型
class CouponDB(Base): class CouponDB(Base):
__tablename__ = "coupons" __tablename__ = "coupons"
@ -18,6 +22,7 @@ class CouponDB(Base):
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), nullable=False) name = Column(String(100), nullable=False)
amount = Column(Float, nullable=False) amount = Column(Float, nullable=False)
coupon_type = Column(Enum(CouponType), nullable=False, default=CouponType.CASH)
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())
@ -28,8 +33,10 @@ class UserCouponDB(Base):
user_id = Column(Integer, ForeignKey("users.userid"), index=True) user_id = Column(Integer, ForeignKey("users.userid"), index=True)
coupon_id = Column(Integer, ForeignKey("coupons.id"), index=True) coupon_id = Column(Integer, ForeignKey("coupons.id"), index=True)
coupon_name = Column(String(100), nullable=False) coupon_name = Column(String(100), nullable=False)
coupon_type = Column(Enum(CouponType), nullable=False)
coupon_amount = Column(Float, nullable=False) coupon_amount = Column(Float, nullable=False)
expire_time = Column(DateTime(timezone=True), nullable=False) expire_time = Column(DateTime(timezone=True), nullable=False)
used_time = Column(DateTime(timezone=True), nullable=True)
status = Column(Enum(CouponStatus), default=CouponStatus.UNUSED) status = Column(Enum(CouponStatus), default=CouponStatus.UNUSED)
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())
@ -37,16 +44,19 @@ class UserCouponDB(Base):
# Pydantic 模型 # Pydantic 模型
class CouponCreate(BaseModel): class CouponCreate(BaseModel):
name: str = Field(..., max_length=100) name: str = Field(..., max_length=100)
amount: float = Field(..., gt=0) amount: Optional[float] = Field(None, gt=0)
coupon_type: CouponType = Field(CouponType.CASH)
class CouponUpdate(BaseModel): class CouponUpdate(BaseModel):
name: Optional[str] = Field(None, max_length=100) name: Optional[str] = Field(None, max_length=100)
amount: Optional[float] = Field(None, gt=0) amount: Optional[float] = Field(None, gt=0)
coupon_type: CouponType = Field(CouponType.CASH)
class CouponInfo(BaseModel): class CouponInfo(BaseModel):
id: int id: int
name: str name: str
amount: float amount: float
coupon_type: CouponType
create_time: datetime create_time: datetime
class Config: class Config:
@ -64,7 +74,9 @@ class UserCouponInfo(BaseModel):
coupon_id: int coupon_id: int
coupon_name: str coupon_name: str
coupon_amount: float coupon_amount: float
coupon_type: CouponType
expire_time: datetime expire_time: datetime
used_time: datetime
status: CouponStatus status: CouponStatus
create_time: datetime create_time: datetime