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

@ -36,6 +36,33 @@ async def create_coupon(
except Exception as e:
db.rollback()
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)
async def update_coupon(

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.models.user import UserDB,UserRole
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 datetime import datetime, timezone
from app.core.config import settings
@ -115,6 +115,7 @@ def calculate_price(price_request: OrderPriceCalculateRequest,user: UserDB,db: S
# 1. 查找用户可用的优惠券(按金额从大到小排序)
available_coupon = db.query(UserCouponDB).filter(
UserCouponDB.user_id == user.userid,
UserCouponDB.coupon_type == CouponType.CASH,
UserCouponDB.status == CouponStatus.UNUSED,
UserCouponDB.expire_time > datetime.now()
).order_by(UserCouponDB.coupon_amount.desc()).first()
@ -192,7 +193,7 @@ async def create_order(
# 查询用户优惠券
if coupon_id:
user_coupon = db.query(UserCouponDB).filter(
UserCouponDB.id == coupon_id
UserCouponDB.id == coupon_id,
).first()
if user_coupon:
@ -268,6 +269,7 @@ async def create_order(
).first()
if coupon:
coupon.status = CouponStatus.USED
coupon.used_time = datetime.now()
# 如果使用了积分,扣减用户积分并记录
if price_result.used_points:
@ -672,6 +674,7 @@ async def cancel_order(
).first()
if coupon:
coupon.status = CouponStatus.UNUSED
coupon.used_time = None
# 检查子订单是否全部取消
sub_orders = db.query(PointProductOrderDB).filter(
@ -877,6 +880,7 @@ async def deliveryman_cancel_order(
).first()
if coupon:
coupon.status = CouponStatus.UNUSED
coupon.used_time = None
# 检查子订单是否全部取消
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.address import AddressDB, AddressInfo
from app.models.user import UserUpdateRoles, UserUpdateDeliveryCommissionRate
from app.models.order import ShippingOrderDB
router = APIRouter()
# Redis 连接
@ -343,6 +345,8 @@ async def password_login(
@router.get("/referrals", response_model=ResponseModel)
async def get_referral_users(
skip: int = 0,
limit: int = 10,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
@ -351,19 +355,30 @@ async def get_referral_users(
UserDB.referral_code == current_user.user_code
).order_by(
UserDB.create_time.desc()
).all()
).offset(skip).limit(limit).all()
# 处理手机号脱敏
def mask_phone(phone: str) -> str:
return f"{phone[:3]}****{phone[7:]}"
total = db.query(UserDB).filter(
UserDB.referral_code == current_user.user_code
).count()
user_list = []
# 获取用户是否下单
for user in referral_users:
u = ReferralUserInfo.model_validate(user).model_dump()
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=[
ReferralUserInfo(
nickname=user.nickname,
phone=mask_phone(user.phone),
create_time=user.create_time
) for user in referral_users
])
return success_response(data={
"total": total,
"items": user_list
})
def issue_register_coupons(db: Session, user_id: int):
"""发放注册优惠券

View File

@ -85,7 +85,6 @@ async def exception_handler(request, exc):
**请求信息**
> 请求方法{request.method}
> 请求URL{request.url}
> 请求头{request.headers}
> 请求体{request.body}
**异常信息**
@ -96,5 +95,8 @@ async def exception_handler(request, exc):
return CustomJSONResponse(
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"
EXPIRED = "EXPIRED"
class CouponType(str, enum.Enum):
PRODUCT = "PRODUCT" # 商品
CASH = "CASH" # 现金
# 数据库模型
class CouponDB(Base):
__tablename__ = "coupons"
@ -18,6 +22,7 @@ class CouponDB(Base):
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), 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())
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)
coupon_id = Column(Integer, ForeignKey("coupons.id"), index=True)
coupon_name = Column(String(100), nullable=False)
coupon_type = Column(Enum(CouponType), nullable=False)
coupon_amount = Column(Float, 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)
create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now())
@ -37,16 +44,19 @@ class UserCouponDB(Base):
# Pydantic 模型
class CouponCreate(BaseModel):
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):
name: Optional[str] = Field(None, max_length=100)
amount: Optional[float] = Field(None, gt=0)
coupon_type: CouponType = Field(CouponType.CASH)
class CouponInfo(BaseModel):
id: int
name: str
amount: float
coupon_type: CouponType
create_time: datetime
class Config:
@ -64,7 +74,9 @@ class UserCouponInfo(BaseModel):
coupon_id: int
coupon_name: str
coupon_amount: float
coupon_type: CouponType
expire_time: datetime
used_time: datetime
status: CouponStatus
create_time: datetime