coupon 增加类型 和 核销功能。
This commit is contained in:
parent
0d2e503965
commit
c0ec42ca8a
@ -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,
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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):
|
||||||
"""发放注册优惠券
|
"""发放注册优惠券
|
||||||
|
|||||||
@ -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)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user