396 lines
14 KiB
Python
396 lines
14 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
||
from sqlalchemy.orm import Session
|
||
from typing import List
|
||
from app.models.merchant_order import (
|
||
MerchantOrderDB,
|
||
MerchantOrderCreate,
|
||
MerchantOrderInfo,
|
||
generate_order_id,
|
||
generate_verify_code,
|
||
MerchantOrderStatus
|
||
)
|
||
from app.models.merchant_product import MerchantProductDB
|
||
from app.models.database import get_db
|
||
from app.api.deps import get_current_user, get_admin_user
|
||
from app.models.user import UserDB
|
||
from app.core.response import success_response, error_response, ResponseModel
|
||
from datetime import datetime, timezone
|
||
from app.models.merchant import MerchantDB
|
||
from app.models.point import PointRecordDB
|
||
from app.core.account import AccountManager
|
||
|
||
router = APIRouter()
|
||
|
||
@router.post("", response_model=ResponseModel)
|
||
async def create_order(
|
||
order: MerchantOrderCreate,
|
||
db: Session = Depends(get_db),
|
||
current_user: UserDB = Depends(get_current_user)
|
||
):
|
||
"""创建商家订单"""
|
||
# 检查商品是否存在
|
||
product = db.query(MerchantProductDB).filter(
|
||
MerchantProductDB.id == order.merchant_product_id
|
||
).first()
|
||
if not product:
|
||
return error_response(code=404, message="商品不存在")
|
||
|
||
# 计算积分抵扣
|
||
available_points = current_user.points or 0
|
||
deduct_amount = min(
|
||
float(product.max_deduct_points),
|
||
available_points
|
||
) if available_points > 0 else 0
|
||
|
||
# 计算实际支付金额
|
||
original_amount = float(product.sale_price)
|
||
pay_amount = max(0, original_amount - deduct_amount)
|
||
|
||
# 生成订单号和核销码
|
||
while True:
|
||
order_id = generate_order_id()
|
||
verify_code = generate_verify_code()
|
||
exists = db.query(MerchantOrderDB).filter(
|
||
(MerchantOrderDB.order_id == order_id) |
|
||
(MerchantOrderDB.order_verify_code == verify_code)
|
||
).first()
|
||
if not exists:
|
||
break
|
||
|
||
# 创建订单
|
||
db_order = MerchantOrderDB(
|
||
order_id=order_id,
|
||
user_id=current_user.userid,
|
||
merchant_product_id=order.merchant_product_id,
|
||
order_amount=original_amount,
|
||
deduct_amount=deduct_amount,
|
||
pay_amount=pay_amount,
|
||
status=MerchantOrderStatus.CREATED,
|
||
order_verify_code=verify_code
|
||
)
|
||
|
||
# 扣除用户积分并记录日志
|
||
if deduct_amount > 0:
|
||
current_user.points -= deduct_amount
|
||
|
||
# 记录积分变动日志
|
||
point_record = PointRecordDB(
|
||
user_id=current_user.userid,
|
||
points=-float(deduct_amount), # 负数表示扣减
|
||
description=f"订单消费抵扣"
|
||
)
|
||
db.add(point_record)
|
||
|
||
db.add(db_order)
|
||
|
||
try:
|
||
db.commit()
|
||
db.refresh(db_order)
|
||
return success_response(data=MerchantOrderInfo.model_validate(db_order))
|
||
except Exception as e:
|
||
db.rollback()
|
||
return error_response(code=500, message=f"创建订单失败: {str(e)}")
|
||
|
||
@router.get("/user", response_model=ResponseModel)
|
||
async def get_user_orders(
|
||
skip: int = 0,
|
||
limit: int = 20,
|
||
db: Session = Depends(get_db),
|
||
current_user: UserDB = Depends(get_current_user)
|
||
):
|
||
"""获取用户的订单列表"""
|
||
orders = db.query(
|
||
MerchantOrderDB,
|
||
MerchantProductDB.name.label('product_name'),
|
||
MerchantProductDB.image_url.label('product_image'),
|
||
MerchantDB.name.label('merchant_name'),
|
||
MerchantDB.latitude.label('merchant_latitude'),
|
||
MerchantDB.longitude.label('merchant_longitude'),
|
||
MerchantDB.phone.label('merchant_phone')
|
||
).join(
|
||
MerchantProductDB,
|
||
MerchantOrderDB.merchant_product_id == MerchantProductDB.id
|
||
).join(
|
||
MerchantDB,
|
||
MerchantProductDB.merchant_id == MerchantDB.id
|
||
).filter(
|
||
MerchantOrderDB.user_id == current_user.userid
|
||
).order_by(
|
||
MerchantOrderDB.create_time.desc()
|
||
).offset(skip).limit(limit).all()
|
||
|
||
# 构建返回数据
|
||
order_list = [{
|
||
"id": order.MerchantOrderDB.id,
|
||
"order_id": order.MerchantOrderDB.order_id,
|
||
"user_id": order.MerchantOrderDB.user_id,
|
||
"merchant_product_id": order.MerchantOrderDB.merchant_product_id,
|
||
"order_amount": order.MerchantOrderDB.order_amount,
|
||
"status": order.MerchantOrderDB.status,
|
||
"order_verify_code": order.MerchantOrderDB.order_verify_code,
|
||
"verify_time": order.MerchantOrderDB.verify_time,
|
||
"verify_user_id": order.MerchantOrderDB.verify_user_id,
|
||
"create_time": order.MerchantOrderDB.create_time,
|
||
"update_time": order.MerchantOrderDB.update_time,
|
||
# 商品信息
|
||
"product_name": order.product_name,
|
||
"product_image": order.product_image,
|
||
# 商家信息
|
||
"merchant_name": order.merchant_name,
|
||
"merchant_latitude": order.merchant_latitude,
|
||
"merchant_longitude": order.merchant_longitude,
|
||
"merchant_phone": order.merchant_phone
|
||
} for order in orders]
|
||
|
||
return success_response(data=order_list)
|
||
|
||
@router.post("/{order_id}/verify", response_model=ResponseModel)
|
||
async def verify_order(
|
||
order_id: str,
|
||
verify_code: str,
|
||
db: Session = Depends(get_db),
|
||
current_user: UserDB = Depends(get_current_user)
|
||
):
|
||
"""核销订单"""
|
||
# 查询订单及相关信息
|
||
order = db.query(
|
||
MerchantOrderDB,
|
||
MerchantProductDB,
|
||
MerchantDB
|
||
).join(
|
||
MerchantProductDB,
|
||
MerchantOrderDB.merchant_product_id == MerchantProductDB.id
|
||
).join(
|
||
MerchantDB,
|
||
MerchantProductDB.merchant_id == MerchantDB.id
|
||
).filter(
|
||
MerchantOrderDB.order_id == order_id,
|
||
MerchantOrderDB.order_verify_code == verify_code,
|
||
MerchantOrderDB.verify_time.is_(None) # 未核销
|
||
).first()
|
||
|
||
if not order:
|
||
return error_response(code=404, message="订单不存在或已核销")
|
||
|
||
try:
|
||
# 更新核销时间和核销用户
|
||
order.MerchantOrderDB.verify_time = datetime.now(timezone.utc)
|
||
order.MerchantOrderDB.verify_user_id = current_user.userid
|
||
order.MerchantOrderDB.status = MerchantOrderStatus.VERIFIED
|
||
|
||
# 使用账户管理器处理余额变更
|
||
account_manager = AccountManager(db)
|
||
settlement_amount = float(order.MerchantProductDB.settlement_amount)
|
||
account_manager.change_balance(
|
||
user_id=order.MerchantDB.user_id,
|
||
amount=settlement_amount,
|
||
description=f"{order.MerchantProductDB.name} 订单核销",
|
||
transaction_id=order.MerchantOrderDB.order_id
|
||
)
|
||
|
||
db.commit()
|
||
return success_response(
|
||
message="核销成功",
|
||
data=MerchantOrderInfo.model_validate(order.MerchantOrderDB)
|
||
)
|
||
except Exception as e:
|
||
db.rollback()
|
||
return error_response(code=500, message=f"核销失败: {str(e)}")
|
||
|
||
@router.post("/{order_id}/unverify", response_model=ResponseModel)
|
||
async def set_order_unverified(
|
||
order_id: str,
|
||
db: Session = Depends(get_db),
|
||
current_user: UserDB = Depends(get_current_user)
|
||
):
|
||
"""设置订单为未核销状态"""
|
||
order = db.query(MerchantOrderDB).filter(
|
||
MerchantOrderDB.order_id == order_id,
|
||
MerchantOrderDB.status == MerchantOrderStatus.CREATED # 只有已下单状态可以设为未核销
|
||
).first()
|
||
|
||
if not order:
|
||
return error_response(code=404, message="订单不存在或状态不正确")
|
||
|
||
# 更新状态为未核销
|
||
order.status = MerchantOrderStatus.UNVERIFIED
|
||
|
||
try:
|
||
db.commit()
|
||
return success_response(
|
||
message="状态更新成功",
|
||
data=MerchantOrderInfo.model_validate(order)
|
||
)
|
||
except Exception as e:
|
||
db.rollback()
|
||
return error_response(code=500, message=f"状态更新失败: {str(e)}")
|
||
|
||
@router.post("/{order_id}/refund/apply", response_model=ResponseModel)
|
||
async def apply_refund(
|
||
order_id: str,
|
||
db: Session = Depends(get_db),
|
||
current_user: UserDB = Depends(get_current_user)
|
||
):
|
||
"""申请退款"""
|
||
order = db.query(MerchantOrderDB).filter(
|
||
MerchantOrderDB.order_id == order_id,
|
||
MerchantOrderDB.user_id == current_user.userid, # 只能申请自己的订单
|
||
MerchantOrderDB.status.in_([MerchantOrderStatus.CREATED, MerchantOrderStatus.UNVERIFIED]) # 只有未核销的订单可以退款
|
||
).first()
|
||
|
||
if not order:
|
||
return error_response(code=404, message="订单不存在或状态不允许退款")
|
||
|
||
# 更新状态为退款中
|
||
order.status = MerchantOrderStatus.REFUNDING
|
||
|
||
try:
|
||
db.commit()
|
||
return success_response(
|
||
message="退款申请成功",
|
||
data=MerchantOrderInfo.model_validate(order)
|
||
)
|
||
except Exception as e:
|
||
db.rollback()
|
||
return error_response(code=500, message=f"申请退款失败: {str(e)}")
|
||
|
||
@router.post("/{order_id}/refund/confirm", response_model=ResponseModel)
|
||
async def confirm_refund(
|
||
order_id: str,
|
||
db: Session = Depends(get_db),
|
||
current_user: UserDB = Depends(get_admin_user)
|
||
):
|
||
"""确认退款(管理员)"""
|
||
# 查询订单和用户信息
|
||
order = db.query(MerchantOrderDB).join(
|
||
UserDB,
|
||
MerchantOrderDB.user_id == UserDB.userid
|
||
).filter(
|
||
MerchantOrderDB.order_id == order_id,
|
||
MerchantOrderDB.status == MerchantOrderStatus.REFUNDING # 只能确认退款中的订单
|
||
).first()
|
||
|
||
if not order:
|
||
return error_response(code=404, message="订单不存在或状态不正确")
|
||
|
||
try:
|
||
# 更新状态为已退款
|
||
order.status = MerchantOrderStatus.REFUNDED
|
||
|
||
# 如果有积分抵扣,返还积分
|
||
if order.deduct_amount > 0:
|
||
# 返还用户积分
|
||
order.user.points += float(order.deduct_amount)
|
||
|
||
point_record = PointRecordDB(
|
||
user_id=order.user_id,
|
||
points=float(order.deduct_amount), # 正数表示返还
|
||
description=f"订单退款返还"
|
||
)
|
||
db.add(point_record)
|
||
|
||
db.commit()
|
||
return success_response(
|
||
message="退款确认成功",
|
||
data=MerchantOrderInfo.model_validate(order)
|
||
)
|
||
except Exception as e:
|
||
db.rollback()
|
||
return error_response(code=500, message=f"确认退款失败: {str(e)}")
|
||
|
||
@router.get("/{order_id}", response_model=ResponseModel)
|
||
async def get_order_detail(
|
||
order_id: str,
|
||
db: Session = Depends(get_db),
|
||
current_user: UserDB = Depends(get_current_user)
|
||
):
|
||
"""获取订单详情"""
|
||
order = db.query(
|
||
MerchantOrderDB,
|
||
MerchantProductDB.name.label('product_name'),
|
||
MerchantProductDB.image_url.label('product_image'),
|
||
MerchantDB.name.label('merchant_name'),
|
||
MerchantDB.latitude.label('merchant_latitude'),
|
||
MerchantDB.longitude.label('merchant_longitude'),
|
||
MerchantDB.phone.label('merchant_phone')
|
||
).join(
|
||
MerchantProductDB,
|
||
MerchantOrderDB.merchant_product_id == MerchantProductDB.id
|
||
).join(
|
||
MerchantDB,
|
||
MerchantProductDB.merchant_id == MerchantDB.id
|
||
).filter(
|
||
MerchantOrderDB.order_id == order_id
|
||
).first()
|
||
|
||
if not order:
|
||
return error_response(code=404, message="订单不存在")
|
||
|
||
# 检查权限
|
||
if order.MerchantOrderDB.user_id != current_user.userid:
|
||
return error_response(code=403, message="无权查看此订单")
|
||
|
||
# 构建返回数据
|
||
order_data = {
|
||
"id": order.MerchantOrderDB.id,
|
||
"order_id": order.MerchantOrderDB.order_id,
|
||
"user_id": order.MerchantOrderDB.user_id,
|
||
"merchant_product_id": order.MerchantOrderDB.merchant_product_id,
|
||
"order_amount": order.MerchantOrderDB.order_amount,
|
||
"status": order.MerchantOrderDB.status,
|
||
"order_verify_code": order.MerchantOrderDB.order_verify_code,
|
||
"verify_time": order.MerchantOrderDB.verify_time,
|
||
"verify_user_id": order.MerchantOrderDB.verify_user_id,
|
||
"create_time": order.MerchantOrderDB.create_time,
|
||
"update_time": order.MerchantOrderDB.update_time,
|
||
# 商品信息
|
||
"product_name": order.product_name,
|
||
"product_image": order.product_image,
|
||
# 商家信息
|
||
"merchant_name": order.merchant_name,
|
||
"merchant_latitude": order.merchant_latitude,
|
||
"merchant_longitude": order.merchant_longitude,
|
||
"merchant_phone": order.merchant_phone
|
||
}
|
||
|
||
return success_response(data=order_data)
|
||
|
||
@router.post("/calculate-price", response_model=ResponseModel)
|
||
async def calculate_order_price(
|
||
order: MerchantOrderCreate,
|
||
db: Session = Depends(get_db),
|
||
current_user: UserDB = Depends(get_current_user)
|
||
):
|
||
"""计算订单价格
|
||
|
||
1. 获取商品信息和用户积分
|
||
2. 计算最高可抵扣金额
|
||
3. 返回最终支付金额
|
||
"""
|
||
# 查询商品信息
|
||
product = db.query(MerchantProductDB).filter(
|
||
MerchantProductDB.id == order.merchant_product_id
|
||
).first()
|
||
|
||
if not product:
|
||
return error_response(code=404, message="商品不存在")
|
||
|
||
# 获取用户积分
|
||
available_points = current_user.points or 0
|
||
|
||
# 计算最高可抵扣金额(1积分 = 1分钱)
|
||
max_deduct_amount = min(
|
||
float(product.max_deduct_points), # 商品最高可抵扣金额
|
||
available_points # 用户可用积分
|
||
) if available_points > 0 else 0
|
||
|
||
# 计算最终支付金额
|
||
final_amount = max(0, float(product.sale_price) - max_deduct_amount)
|
||
|
||
return success_response(data={
|
||
"original_price": float(product.sale_price),
|
||
"available_points": available_points,
|
||
"max_deduct_points": float(product.max_deduct_points),
|
||
"max_deduct_amount": max_deduct_amount,
|
||
"final_amount": final_amount
|
||
}) |