deliveryman-api/app/api/endpoints/order.py
2025-03-30 16:52:57 +08:00

1751 lines
65 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from app.core.account import AccountManager
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from typing import List, Optional
from app.models.order import (
ShippingOrderDB,
ShippingOrderPackageDB,
OrderCreate,
OrderInfo,
OrderPackageInfo,
OrderPriceCalculateRequest,
OrderPriceInfo,
OrderStatus,
OrderCancel,
OrderComplete,
OrderPriceResult
)
from app.models.order_additional_fee import OrderAdditionalFeeDB, OrderAdditionalFeeInfo, AdditionalFeeResult
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, CouponType
from app.models.point_product_order import PointProductOrderDB, PointProductOrderInfo, PointProductOrderStatus
from datetime import datetime, timezone
from app.core.config import settings
from app.models.address import AddressDB
from sqlalchemy.orm import joinedload
from app.models.community import CommunityDB
from app.models.community_building import CommunityBuildingDB, CommunityBuildingInfo
from app.models.station import StationDB
from app.models.point import PointRecordDB, PointRecordType
from app.core.utils import CommonUtils
import logging
from sqlalchemy import func
from app.core.mpclient import mp_client
from datetime import timedelta
from app.core.imageprocessor import process_image, ImageFormat
from app.core.point_manager import PointManager
from datetime import time
from app.core.wecombot import WecomBot
from app.models.config import ConfigDB
from app.core.mpmessage import sent_order_status_change_message
from fastapi import BackgroundTasks
from app.core.coupon_manager import CouponManager
from app.core.redis_client import redis_client
from app.models.timeperiod import TimePeriodDB
from app.models.community_timeperiod import CommunityTimePeriodDB
from app.models.community_profit_sharing import CommunityProfitSharing
from app.core.qcloud import QCloudManager
router = APIRouter()
def calculate_price(price_request: OrderPriceCalculateRequest,user: UserDB,db: Session) -> OrderPriceResult:
"""
计算订单价格,自动使用优惠券或积分抵扣
Args:
price_request: 价格计算请求
user: 用户信息
Returns:
OrderPriceResult: 包含价格信息和使用的优惠券/积分信息
"""
# 计算所有包裹中的取件码总数
pickup_code_count = 0
pickup_images_count = 0
package_count = 0
if price_request.pickup_images:
pickup_images_count = price_request.pickup_images_count
if price_request.packages:
pickup_code_count = sum(
# 如果package.pickup_codes是空字符串则取0
0 if len(package.pickup_codes.split(',')) == 0 else len(package.pickup_codes.split(','))
for package in price_request.packages
if package.pickup_codes
)
package_count = pickup_code_count + pickup_images_count
result = OrderPriceResult(
price_info=OrderPriceInfo(
package_count=package_count,
pickup_images_count=pickup_images_count,
pickup_code_count=pickup_code_count,
coupon_discount_amount=0,
points_discount_amount=0,
original_amount=0,
base_delivery_amount=0,
more_station_price=0,
final_amount=0
)
)
# 默认定价
base_price = settings.ORDER_BASE_PRICE
extra_package_price = settings.ORDER_EXTRA_PACKAGE_PRICE
extra_package_threshold = settings.ORDER_EXTRA_PACKAGE_THRESHOLD
base_more_station_price = 0
# 获取小区定价
if price_request.community_id > 0:
community = db.query(CommunityDB).filter(
CommunityDB.id == price_request.community_id
).first()
if community:
base_price = float(community.base_price)
extra_package_price = float(community.extra_package_price)
extra_package_threshold = int(community.extra_package_threshold)
base_more_station_price = float(community.more_station_price)
# 是否有多驿站
more_station_price = float(community.more_station_price) * (len(price_request.packages) - 1) if len(price_request.packages) > 1 else 0
base_delivery_amount = round(base_price + extra_package_price * max(0, package_count - extra_package_threshold), 2)
original_amount = round(more_station_price + base_delivery_amount, 2)
result.price_info.package_count = package_count
result.price_info.pickup_images_count = pickup_images_count
result.price_info.pickup_code_count = pickup_code_count
result.price_info.original_amount = original_amount
result.price_info.more_station_price = more_station_price
result.price_info.final_amount = original_amount
result.price_info.base_delivery_amount = base_delivery_amount
remaining_amount = original_amount
# 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()
# 2. 如果有可用优惠券,优先使用优惠券
if available_coupon:
coupon_discount = min(remaining_amount, available_coupon.coupon_amount)
result.price_info.coupon_discount_amount = coupon_discount
result.price_info.coupon_id = available_coupon.id
result.used_coupon_id = available_coupon.id
remaining_amount -= coupon_discount
# 3. 如果没有优惠券,且用户有积分,则使用积分抵扣
elif user.points > 0:
# 计算最大可抵扣金额
max_points_discount = user.points // settings.POINT_RATIO # 使用整除
points_discount_amount = min(remaining_amount, max_points_discount)
if points_discount_amount > 0:
result.price_info.points_discount_amount = points_discount_amount
result.used_points = int(points_discount_amount * settings.POINT_RATIO)
remaining_amount -= points_discount_amount
# 计算最终金额
result.price_info.final_amount = round(remaining_amount, 2)
# 计算价格详情
result.price_detail_text = f"* 基础费{round(base_price, 1)}元(含1个驿站和{extra_package_threshold}件包裹), 超件{round(extra_package_price, 1)}元/件\r\n* 超过1个驿站, 增加配送路程, 加收{round(base_more_station_price, 1)}元/驿站"
return result
def calculate_delivery_share(order: ShippingOrderDB, db: Session) -> float:
# 获取对应小区的分润
sharing = db.query(CommunityProfitSharing).filter(
CommunityProfitSharing.community_id == order.address_community_id
).first()
if sharing:
return round(order.original_amount_with_additional_fee * (float(sharing.delivery_rate) / 100.0), 2)
else:
return 0
def format_delivery_time(delivery_date: datetime, time_period_name: str) -> str:
if delivery_date == datetime.now().date():
return f"今日 {time_period_name}"
elif delivery_date == datetime.now().date() + timedelta(days=1):
return f"明日 {time_period_name}"
elif delivery_date == datetime.now().date() - timedelta(days=1):
return f"昨日 {time_period_name}"
else:
return f"{delivery_date.strftime('%m-%d')} {time_period_name}"
def has_consecutive_weekdays(weekdays):
if not weekdays or len(weekdays) <= 1:
return True
days = sorted(weekdays)
# 处理环绕情况
if 1 in days and 7 in days and abs(days.index(1) - days.index(7)) == 1:
# 特殊处理周日和周一的连接
temp = days.copy()
temp.remove(1 if days.index(1) == 0 else 7)
return all(temp[i] - temp[i-1] == 1 for i in range(1, len(temp)))
# 普通情况
return all(days[i] - days[i-1] == 1 for i in range(1, len(days)))
@router.post("/pre-order", response_model=ResponseModel)
async def pre_order(
request: OrderPriceCalculateRequest,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
try:
# 检查delivery_date是否是今天以前的日期则提示重新选择
if request.delivery_date and request.delivery_date < datetime.now().date():
return error_response(code=400, message="配送日期不能选择过去的时间")
# 检查是否在服务时间
community = db.query(CommunityDB).filter(
CommunityDB.id == request.community_id
).first()
if community:
# 检查是否在服务时间
if community.weekdays and request.delivery_date:
if request.delivery_date.isoweekday() not in community.weekdays:
#排序
sorted_weekdays = sorted(community.weekdays)
if has_consecutive_weekdays(sorted_weekdays):
message = f"服务时间为: 周{sorted_weekdays[0]}-{sorted_weekdays[-1]}"
else:
message = f"服务时间为: "
for day in sorted_weekdays:
message += f"{day}, "
message = message[:-2]
return error_response(code=400, message=message)
# 检查是否有配送员在线
# deliveryman_online = db.query(UserDB).filter(
# UserDB.roles.contains(UserRole.DELIVERYMAN),
# UserDB.community_id == request.community_id,
# UserDB.is_delivering == True
# ).first()
# if deliveryman_online is None:
# print(f"没有配送员在线, 无法下单")
# return error_response(code=400, message="没有配送员在线, 无法下单")
# 检查是否有未支付的订单
unpay_order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.userid == current_user.userid,
ShippingOrderDB.status == OrderStatus.UNPAID
).first()
if unpay_order:
return error_response(code=400, message="存在未完成的订单", data={
"orderid": unpay_order.orderid
})
"""预下单 - 计算价格"""
price_info = calculate_price(request, current_user, db)
return success_response(data=price_info)
except Exception as e:
logging.exception(f"预下单失败: {str(e)}")
return error_response(code=500, message=f"预下单失败: {str(e)}")
@router.post("", response_model=ResponseModel)
async def create_order(
background_tasks: BackgroundTasks,
order: OrderCreate,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
"""创建配送订单"""
# 计算订单价格
price_result = calculate_price(order.price_request, current_user, db)
price_info = price_result.price_info
# 生成订单号
orderid = CommonUtils.generate_order_id('D')
# 计算原始金额
original_amount = price_info.original_amount
# 计算优惠券折扣
coupon_discount = price_info.coupon_discount_amount
coupon_id = price_info.coupon_id
# 查询用户优惠券
if coupon_id:
user_coupon = db.query(UserCouponDB).filter(
UserCouponDB.id == coupon_id,
).first()
if user_coupon:
coupon_discount = user_coupon.coupon_amount
coupon_id = user_coupon.id
# 更新优惠券状态
user_coupon.status = CouponStatus.USED
# 查询地址信息
address = db.query(AddressDB).filter(
AddressDB.id == order.addressid
).first()
# 是否为新人订单
is_first_order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.userid == current_user.userid,
ShippingOrderDB.status != OrderStatus.CANCELLED
).count() == 0
# 创建订单
db_order = ShippingOrderDB(
orderid=orderid,
userid=current_user.userid,
address_customer_name=address.name,
address_customer_phone=address.phone,
address_customer_gender=address.gender,
address_community_id=address.community_id,
address_community_building_id=address.community_building_id,
address_community_name=address.community_name,
address_community_building_name=address.community_building_name,
address_detail=address.address_detail,
package_count=price_info.package_count,
pickup_images_count=price_info.pickup_images_count,
pickup_code_count=price_info.pickup_code_count,
original_amount=original_amount,
coupon_discount_amount=coupon_discount,
point_discount_amount=price_info.points_discount_amount,
more_station_price=price_info.more_station_price,
coupon_id=coupon_id,
final_amount=price_info.final_amount,
status=OrderStatus.CREATED,
delivery_method=order.delivery_method,
delivery_date=order.delivery_date,
is_first_order=is_first_order
)
# 获取社区配送时段
community_time_period = db.query(CommunityTimePeriodDB,
TimePeriodDB.name.label('time_period_name'),
TimePeriodDB.from_time.label('time_period_from_time'),
TimePeriodDB.to_time.label('time_period_to_time')).filter(
CommunityTimePeriodDB.id == order.community_time_period_id
).join(TimePeriodDB,
CommunityTimePeriodDB.time_period_id == TimePeriodDB.id).first()
if community_time_period:
db_order.time_period_id = community_time_period.CommunityTimePeriodDB.time_period_id
db_order.time_period_name = community_time_period.time_period_name
db_order.time_period_from_time = community_time_period.time_period_from_time
db_order.time_period_to_time = community_time_period.time_period_to_time
# 获取取件图片
if order.price_request.pickup_images:
db_order.pickup_images = order.price_request.pickup_images
db.add(db_order)
# 创建订单包裹
if order.price_request.packages:
for package in order.price_request.packages:
# 如果包裹有取件码,则创建包裹
if len(package.pickup_codes) > 0:
if not package.station_name:
station = db.query(StationDB).filter(
StationDB.id == package.station_id
).first()
if station:
station_name = station.name
else:
station_name = "未知驿站"
else:
station_name = package.station_name
# 对package.pickup_codes中分割的取件码进行排序
sorted_pickup_codes = CommonUtils.sort_strings_by_first_number(package.pickup_codes.split(","))
db_package = ShippingOrderPackageDB(
orderid=orderid,
station_id=package.station_id,
station_name=station_name,
pickup_codes=','.join(sorted_pickup_codes)
)
db.add(db_package)
try:
# 如果使用了优惠券,更新优惠券状态
if price_result.used_coupon_id:
coupon = db.query(UserCouponDB).filter(
UserCouponDB.id == price_result.used_coupon_id,
).first()
if coupon:
coupon.status = CouponStatus.USED
coupon.used_time = datetime.now()
# 如果使用了积分,扣减用户积分并记录
if price_result.used_points:
# 扣减用户积分
current_user.points -= price_result.used_points
# 记录积分变动
point_record = PointRecordDB(
user_id=current_user.userid,
points=-price_result.used_points, # 负数表示扣减
type=PointRecordType.CONSUME_DEDUCT,
order_id=db_order.orderid,
description=f"配送订单抵扣积分"
)
db.add(point_record)
db.commit()
db.refresh(db_order)
# 查询包裹信息
packages = db.query(ShippingOrderPackageDB).filter(
ShippingOrderPackageDB.orderid == orderid
).all()
# 发送企业微信消息
wecom_bot = WecomBot()
order_info = OrderInfo.model_validate(db_order)
background_tasks.add_task(
wecom_bot.send_order_notification,
db,
order_info,
OrderStatus.CREATED
)
#发送订单创建成功的公众号消息
if current_user.mp_openid:
data={
"character_string13": db_order.orderid,
"time4": db_order.create_time.strftime("%Y-%m-%d %H:%M:%S"),
"thing10": db_order.address_customer_name,
"thing15": f"{db_order.address_community_name} {db_order.address_community_building_name} {db_order.address_detail}",
"thing9": db_order.status.status_text
}
background_tasks.add_task(
sent_order_status_change_message,
openid=current_user.mp_openid,
template_id=settings.DELIVERY_ORDER_CREATED_TEMPLATE_ID,
data=data,
orderid=db_order.orderid
)
# 添加到新订单队列
if db_order.address_community_id:
background_tasks.add_task(
redis_client.push_new_order_to_queue,
db_order.address_community_id,
db_order.orderid,
db
)
# 今日订单加入今日选中的配送时段的 Redis 消息队列
background_tasks.add_task(
redis_client.push_order_to_community_period_queue,
db_order.delivery_date,
order.community_time_period_id,
db_order.orderid
)
return success_response(
message="订单创建成功",
data={
"order": OrderInfo.model_validate(db_order),
"packages": [OrderPackageInfo.model_validate(p) for p in packages],
"delivery_time": format_delivery_time(db_order.delivery_date, db_order.time_period_name),
"success_text" : f"预计 {format_delivery_time(db_order.delivery_date, db_order.time_period_name)} 送达,请注意查收"
}
)
except Exception as e:
db.rollback()
logging.exception(f"订单创建失败: {str(e)}")
return error_response(code=500, message=f"订单创建失败: {str(e)}")
@router.get("/{orderid}", response_model=ResponseModel)
async def get_order_detail(
orderid: str,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
"""获取订单详情"""
# 使用 join 查询获取订单和相关地址信息
order = db.query(
ShippingOrderDB
).filter(
ShippingOrderDB.orderid == orderid
).first()
if not order:
return error_response(code=404, message="订单不存在")
# 如果有配送员 id则获取配送员信息
if order.deliveryman_user_id:
deliveryman_user = db.query(UserDB).filter(
UserDB.userid == order.deliveryman_user_id
).first()
if deliveryman_user:
deliveryman_user_name = deliveryman_user.nickname
deliveryman_user_avatar = deliveryman_user.optimized_avatar
deliveryman_user_phone = deliveryman_user.phone
delivery_count = db.query(ShippingOrderDB).filter(
ShippingOrderDB.deliveryman_user_id == order.deliveryman_user_id,
ShippingOrderDB.status == OrderStatus.COMPLETED
).count()
else:
delivery_count = 0
deliveryman_user_name = None
deliveryman_user_avatar = None
deliveryman_user_phone = None
# 查询包裹信息
packages = db.query(
ShippingOrderPackageDB
).filter(
ShippingOrderPackageDB.orderid == orderid
).all()
if packages:
# 构建包裹信息,包含驿站名称
package_list = [{
"id": p.id,
"orderid": p.orderid,
"station_id": p.station_id,
"station_name": p.station_name,
"pickup_codes": CommonUtils.sort_strings_by_first_number(p.pickup_codes.split(",")),
"create_time": p.create_time
} for p in packages]
else:
package_list = []
# 获取加价请求
request = db.query(OrderAdditionalFeeDB,
UserDB.nickname.label("deliveryman_name"),
UserDB.phone.label("deliveryman_phone"),
UserDB.avatar.label("deliveryman_avatar")).join(UserDB,
OrderAdditionalFeeDB.deliveryman_id == UserDB.userid).filter(
OrderAdditionalFeeDB.orderid == order.orderid,
OrderAdditionalFeeDB.result == AdditionalFeeResult.PENDING
).first()
order_additional_fee = None
if request:
order_additional_fee = {
"id": request.OrderAdditionalFeeDB.id,
"orderid": request.OrderAdditionalFeeDB.orderid,
"order_user_id": request.OrderAdditionalFeeDB.order_user_id,
"deliveryman_id": request.OrderAdditionalFeeDB.deliveryman_id,
"deliveryman_name": request.deliveryman_name,
"deliveryman_phone": request.deliveryman_phone,
"deliveryman_avatar": request.deliveryman_avatar,
"reason": request.OrderAdditionalFeeDB.reason,
"photo_urls": request.OrderAdditionalFeeDB.photo_urls,
"additional_fee_amount": request.OrderAdditionalFeeDB.additional_fee_amount,
"result": request.OrderAdditionalFeeDB.result,
}
# 计算配送时间
delivery_time = format_delivery_time(order.delivery_date, order.time_period_name)
# 计算配送员配送费用
deliveryman_share = order.delivery_share if order.delivery_share > 0 else calculate_delivery_share(order, db)
base_delivery_amount = order.original_amount - (order.more_station_price if order.more_station_price is not None else 0)
# 构建响应数据
order_data = {
"orderid": order.orderid,
"userid": order.userid,
"pickup_images": order.optimized_pickup_images,
"package_count": order.package_count,
"pickup_code_count": order.pickup_code_count,
"pickup_images_count": order.pickup_images_count,
"original_amount": order.original_amount,
"base_delivery_amount": base_delivery_amount,
"coupon_discount_amount": order.coupon_discount_amount,
"point_discount_amount": order.point_discount_amount,
"more_station_price": order.more_station_price,
"additional_fee_amount": order.additional_fee_amount,
"coupon_id": order.coupon_id,
"final_amount": order.final_amount,
"deliveryman_share": deliveryman_share,
"status": order.status,
"complete_images": order.optimized_complete_images,
"packages": package_list,
"is_first_order": order.is_first_order,
"cancel_reason": order.cancel_reason,
"order_additional_fee": order_additional_fee,
"create_time": order.create_time,
"complete_time": order.completed_time,
"pickup_time": order.pickup_time,
"received_time": order.received_time,
"delivery_date": order.delivery_date,
"delivery_method": order.delivery_method,
"deliveryman_user_id": order.deliveryman_user_id,
"deliveryman_nickname": deliveryman_user_name,
"deliveryman_avatar": deliveryman_user_avatar,
"deliveryman_phone": deliveryman_user_phone,
"delivery_count": delivery_count,
# 地址相关信息
"address_name": order.address_customer_name,
"address_phone": order.address_customer_phone,
"address_detail": order.address_detail,
"address_gender": order.address_customer_gender,
"building_id": order.address_community_building_id,
"building_name": order.address_community_building_name,
"community_id": order.address_community_id,
"community_name": order.address_community_name,
# 配送时段
"time_period_id": order.time_period_id,
"time_period_name": order.time_period_name,
"time_period_from_time": order.time_period_from_time,
"time_period_to_time": order.time_period_to_time,
# 配送时间
"delivery_time": delivery_time
}
return success_response(data=order_data)
# 提供一个接口传入community_id返回订单状态数量
@router.get("/status/count", response_model=ResponseModel)
async def deliveryman_get_order_status_count(
community_id: int,
time_period_id: Optional[int] = None,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
"""获取社区订单状态数量"""
status_list = [OrderStatus.CREATED, OrderStatus.RECEIVED, OrderStatus.DELIVERING, OrderStatus.UNPAID, OrderStatus.COMPLETED]
result = []
for status in status_list:
query = db.query(
ShippingOrderDB.status
).filter(
ShippingOrderDB.address_community_id == community_id,
ShippingOrderDB.status == status
)
# 如果传入了时间周期id则过滤时间周期
if time_period_id:
query = query.filter(
ShippingOrderDB.time_period_id == time_period_id
)
# 不是待接单的订单,需要过滤配送员
if status != OrderStatus.CREATED:
query = query.filter(
ShippingOrderDB.deliveryman_user_id == current_user.userid
)
# 待接单的订单,只显示今天以及今天以前的订单
# if status == OrderStatus.CREATED:
# query = query.filter(
# ShippingOrderDB.delivery_date <= datetime.now().date()
# )
count = query.count()
result.append({
"status": status,
"count": count
})
return success_response(data=result)
# 提供一个接口,传入 community_id 返回每栋楼栋的订单数量
@router.get("/community_building/count", response_model=ResponseModel)
async def deliveryman_get_community_building_order_count(
community_id: int,
status: str,
time_period_id: Optional[int] = None,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
"""获取社区每栋楼栋的订单数量"""
# 查询当前社区所有楼栋
community_buildings = db.query(
CommunityBuildingDB
).filter(
CommunityBuildingDB.community_id == community_id
).all()
if not community_buildings:
return error_response(code=404, message="社区不存在")
# 查询每个楼栋的订单数量
query = db.query(
ShippingOrderDB.address_community_building_id,
func.count(ShippingOrderDB.orderid)
).filter(
ShippingOrderDB.address_community_building_id.in_(
[building.id for building in community_buildings]
)
).filter(
ShippingOrderDB.status.in_(status.split(","))
)
# 如果传入了时间周期id则过滤时间周期
if time_period_id:
query = query.filter(
ShippingOrderDB.time_period_id == time_period_id
)
# 如果订单状态不是待接单,则需要过滤快递员
if OrderStatus.CREATED not in status:
query = query.filter(
ShippingOrderDB.deliveryman_user_id == current_user.userid
)
# 待接单的订单,只显示今天以及今天以前的订单
# if OrderStatus.CREATED in status:
# query = query.filter(
# ShippingOrderDB.delivery_date <= datetime.now().date()
# )
building_order_count = query.group_by(
ShippingOrderDB.address_community_building_id
).all()
# 没有订单的楼栋订单数量为0
result = []
building_order_count_dict = dict(building_order_count)
for building in community_buildings:
if building.id not in building_order_count_dict:
result.append({
"building_id": building.id,
"building_name": building.building_name,
"order_count": 0
})
else:
result.append({
"building_id": building.id,
"building_name": building.building_name,
"order_count": building_order_count_dict[building.id]
})
return success_response(data=result)
@router.get("/user/list", response_model=ResponseModel)
async def get_user_orders(
status: Optional[OrderStatus] = None,
skip: int = 0,
limit: int = 20,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
"""获取用户订单列表"""
try:
# 查询订单
query = db.query(
ShippingOrderDB
).filter(
ShippingOrderDB.userid == current_user.userid
)
# 添加状态过滤
if status:
query = query.filter(ShippingOrderDB.status == status)
# 获取总数
total = query.count()
# 分页查询
results = query.order_by(
ShippingOrderDB.create_time.desc()
).offset(skip).limit(limit).all()
orders = []
for order in results:
# 查询订单包裹信息
packages = db.query(
ShippingOrderPackageDB
).filter(
ShippingOrderPackageDB.orderid == order.orderid
).all()
# 格式化包裹信息
if packages:
package_list = [{
"id": package.id,
"station_id": package.station_id,
"station_name": package.station_name,
"pickup_codes": package.pickup_codes
} for package in packages]
else:
package_list = []
#查询子订单
sub_orders = db.query(PointProductOrderDB).filter(
PointProductOrderDB.delivery_order_id == order.orderid
).all()
orders.append({
"orderid": order.orderid,
"userid": order.userid,
"status": order.status,
"pickup_images": order.optimized_pickup_images,
"package_count": order.package_count,
"pickup_code_count": order.pickup_code_count,
"pickup_images_count": order.pickup_images_count,
"create_time": order.create_time,
"delivery_method": order.delivery_method,
"original_amount": order.original_amount,
"coupon_discount_amount": order.coupon_discount_amount,
"point_discount_amount": order.point_discount_amount,
"final_amount": order.final_amount,
"is_first_order": order.is_first_order,
"packages": package_list,
"sub_orders": [PointProductOrderInfo.model_validate(sub_order) for sub_order in sub_orders],
"address": {
"name": order.address_customer_name,
"phone": order.address_customer_phone,
"gender": order.address_customer_gender,
"community_id": order.address_community_id,
"community_name": order.address_community_name,
"building_id": order.address_community_building_id,
"building_name": order.address_community_building_name,
"address_detail": order.address_detail
},
"complete_images": order.optimized_complete_images,
"received_time": order.received_time,
"pickup_time": order.pickup_time,
"completed_time": order.completed_time
})
return success_response(data={
"total": total,
"items": orders
})
except Exception as e:
return error_response(code=500, message=f"获取订单列表失败: {str(e)}")
@router.post("/{orderid}/user/cancel", response_model=ResponseModel)
async def cancel_order(
background_tasks: BackgroundTasks,
orderid: str,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_current_user)
):
"""取消订单"""
# 查询订单
order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.orderid == orderid,
ShippingOrderDB.userid == current_user.userid
).first()
if not order:
return error_response(code=404, message="订单不存在")
# 检查订单状态是否可取消
if order.status not in [OrderStatus.CREATED, OrderStatus.RECEIVED]:
return error_response(code=400, message="当前订单状态不可取消")
try:
# 更新订单状态、取消原因和取消用户
order.status = OrderStatus.CANCELLED
order.cancel_reason = "用户主动取消"
order.cancel_user_id = current_user.userid # 记录取消订单的用户ID
# 如果使用了优惠券,返还优惠券
if order.coupon_id:
coupon = db.query(UserCouponDB).filter(
UserCouponDB.id == order.coupon_id
).first()
if coupon:
coupon.status = CouponStatus.UNUSED
coupon.used_time = None
# 检查子订单是否全部取消
sub_orders = db.query(PointProductOrderDB).filter(
PointProductOrderDB.delivery_order_id == order.orderid
).all()
if sub_orders:
for sub_order in sub_orders:
sub_order.status = PointProductOrderStatus.CANCELLED
#返还积分
point_manager = PointManager(db)
point_manager.add_points(
user_id=current_user.userid,
points=sub_order.order_point_amount,
description=f"兑换订单取消返还",
order_id=order.orderid
)
# 如果使用了积分,返还积分
if order.point_discount_amount > 0:
# 返还积分
return_points = int(order.point_discount_amount * settings.POINT_RATIO)
point_manager = PointManager(db)
point_manager.add_points(
user_id=current_user.userid,
points=return_points,
description=f"配送订单取消返还",
order_id=order.orderid
)
db.commit()
# 发送企业微信消息
wecom_bot = WecomBot()
order_info = OrderInfo.model_validate(order)
background_tasks.add_task(
wecom_bot.send_order_notification,
db,
order_info,
OrderStatus.CANCELLED
)
# 发送模板消息
if current_user.mp_openid:
data={
"character_string1": order.orderid,
"time19": CommonUtils.get_current_time(),
"thing5": "用户主动取消订单"
}
background_tasks.add_task(
sent_order_status_change_message,
openid=current_user.mp_openid,
template_id=settings.DELIVERY_ORDER_CANCELLED_TEMPLATE_ID,
data=data,
orderid=order.orderid
)
return success_response(
message="订单取消成功",
data=OrderInfo.model_validate(order)
)
except Exception as e:
db.rollback()
return error_response(code=500, message=f"取消订单失败: {str(e)}")
@router.get("/deliveryman/list", response_model=ResponseModel)
async def deliveryman_orders(
status: Optional[str] = None,
building_id: Optional[int] = None,
community_id: Optional[int] = None,
time_period_id: Optional[int] = None,
skip: int = 0,
limit: int = 20,
db: Session = Depends(get_db),
deliveryman: UserDB = Depends(get_deliveryman_user)
):
"""获取配送员订单列表"""
# 基础查询
query = db.query(
ShippingOrderDB
)
# 状态筛选
if status:
statuses = status.split(",")
query = query.filter(ShippingOrderDB.status.in_(statuses))
# 如果订单状态不是待接单,则需要过滤快递员
if OrderStatus.CREATED not in statuses:
query = query.filter(ShippingOrderDB.deliveryman_user_id == deliveryman.userid)
# 待接单的订单,只显示今天以及今天以前的订单
# if OrderStatus.CREATED in statuses:
# query = query.filter(ShippingOrderDB.delivery_date <= datetime.now().date())
# 楼栋筛选
if building_id:
query = query.filter(ShippingOrderDB.address_community_building_id == building_id)
# 小区筛选
if community_id:
query = query.filter(ShippingOrderDB.address_community_id == community_id)
# 配送时段筛选
if time_period_id:
query = query.filter(ShippingOrderDB.time_period_id == time_period_id)
# 获取总数
total = query.count()
# 获取分页数据
results = query.order_by(
ShippingOrderDB.delivery_date.desc(),
ShippingOrderDB.time_period_from_time.asc()
).offset(skip).limit(limit).all()
# 格式化返回数据
orders = []
for order in results:
# 查询订单包裹信息
packages = db.query(
ShippingOrderPackageDB
).filter(
ShippingOrderPackageDB.orderid == order.orderid
).all()
# 格式化包裹信息
if packages:
package_list = [{
"id": package.id,
"station_id": package.station_id,
"station_name": package.station_name,
"pickup_codes": CommonUtils.sort_strings_by_first_number(package.pickup_codes.split(","))
} for package in packages]
else:
package_list = []
# 查询子订单
sub_orders = db.query(PointProductOrderDB).filter(
PointProductOrderDB.delivery_order_id == order.orderid
).all()
# 获取加价请求
requests = db.query(OrderAdditionalFeeDB,
UserDB.nickname.label("deliveryman_name"),
UserDB.phone.label("deliveryman_phone"),
UserDB.avatar.label("deliveryman_avatar")).join(UserDB,
OrderAdditionalFeeDB.deliveryman_id == UserDB.userid).filter(
OrderAdditionalFeeDB.orderid == order.orderid
).all()
order_additional_fees = []
if requests:
for fee in requests:
order_additional_fees.append({
"id": fee.OrderAdditionalFeeDB.id,
"orderid": fee.OrderAdditionalFeeDB.orderid,
"order_user_id": fee.OrderAdditionalFeeDB.order_user_id,
"deliveryman_id": fee.OrderAdditionalFeeDB.deliveryman_id,
"deliveryman_name": fee.deliveryman_name,
"deliveryman_phone": fee.deliveryman_phone,
"deliveryman_avatar": fee.deliveryman_avatar,
"reason": fee.OrderAdditionalFeeDB.reason,
"photo_urls": fee.OrderAdditionalFeeDB.photo_urls,
"additional_fee_amount": fee.OrderAdditionalFeeDB.additional_fee_amount,
"result": fee.OrderAdditionalFeeDB.result,
})
delivery_time = format_delivery_time(order.delivery_date, order.time_period_name)
orders.append({
"orderid": order.orderid,
"userid": order.userid,
"status": order.status,
"pickup_images": order.optimized_pickup_images,
"package_count": order.package_count,
"pickup_code_count": order.pickup_code_count,
"pickup_images_count": order.pickup_images_count,
"create_time": order.create_time,
"delivery_method": order.delivery_method,
"delivery_time": delivery_time,
"original_amount": order.original_amount,
"coupon_discount_amount": order.coupon_discount_amount,
"point_discount_amount": order.point_discount_amount,
"final_amount": order.final_amount,
"is_first_order": order.is_first_order,
"packages": package_list,
"order_additional_fees": order_additional_fees,
"sub_orders": [PointProductOrderInfo.model_validate(sub_order) for sub_order in sub_orders],
"address": {
"name": order.address_customer_name,
"phone": order.address_customer_phone,
"gender": order.address_customer_gender,
"community_id": order.address_community_id,
"community_name": order.address_community_name,
"building_id": order.address_community_building_id,
"building_name": order.address_community_building_name,
"address_detail": order.address_detail
},
"complete_images": order.optimized_complete_images,
"received_time": order.received_time,
"pickup_time": order.pickup_time,
"completed_time": order.completed_time,
"time_period_id": order.time_period_id,
"time_period_name": order.time_period_name,
"time_period_from_time": order.time_period_from_time,
"time_period_to_time": order.time_period_to_time
})
return success_response(data={
"total": total,
"items": orders
})
@router.post("/{orderid}/deliveryman/cancel", response_model=ResponseModel)
async def deliveryman_cancel_order(
background_tasks: BackgroundTasks,
orderid: str,
cancel_data: OrderCancel,
db: Session = Depends(get_db),
deliveryman: UserDB = Depends(get_deliveryman_user)
):
"""配送员取消订单"""
order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.orderid == orderid
).first()
if not order:
return error_response(code=404, message="订单不存在")
# 检查订单状态
if order.status != OrderStatus.CREATED and order.status != OrderStatus.RECEIVED:
return error_response(code=400, message="只有未接单或者已接单的订单才能取消")
try:
# 更新订单状态、取消原因和取消用户
order.status = OrderStatus.CANCELLED
order.cancel_reason = cancel_data.reason
order.cancel_user_id = deliveryman.userid
# 如果使用了优惠券,返还优惠券
if order.coupon_id:
coupon = db.query(UserCouponDB).filter(
UserCouponDB.id == order.coupon_id
).first()
if coupon:
coupon.status = CouponStatus.UNUSED
coupon.used_time = None
# 检查子订单是否全部取消
sub_orders = db.query(PointProductOrderDB).filter(
PointProductOrderDB.delivery_order_id == order.orderid,
PointProductOrderDB.status != PointProductOrderStatus.CANCELLED
).all()
if sub_orders:
for sub_order in sub_orders:
sub_order.status = PointProductOrderStatus.CANCELLED
#返还积分
point_manager = PointManager(db)
point_manager.add_points(
user_id=order.userid,
points=sub_order.order_point_amount,
description=f"兑换订单取消返还",
order_id=order.orderid
)
# 如果使用了积分,返还积分
if order.point_discount_amount > 0:
# 返还积分
return_points = int(order.point_discount_amount * settings.POINT_RATIO)
point_manager = PointManager(db)
point_manager.add_points(
user_id=order.userid,
points=return_points,
description=f"配送订单取消返还",
order_id=order.orderid
)
db.commit()
# 发送企业微信消息
wecom_bot = WecomBot()
order_info = OrderInfo.model_validate(order)
background_tasks.add_task(
wecom_bot.send_order_notification,
db,
order_info,
OrderStatus.CANCELLED
)
# 发送模板消息
if order.userid:
order_user = db.query(UserDB).filter(
UserDB.userid == order.userid
).first()
if order_user.mp_openid:
data={
"character_string1": order.orderid,
"time19": CommonUtils.get_current_time(),
"thing5": order.cancel_reason
}
background_tasks.add_task(
sent_order_status_change_message,
openid=order_user.mp_openid,
template_id=settings.DELIVERY_ORDER_CANCELLED_TEMPLATE_ID,
data=data,
orderid=order.orderid
)
return success_response(
message="订单取消成功",
data=OrderInfo.model_validate(order)
)
except Exception as e:
db.rollback()
return error_response(code=500, message=f"取消订单失败: {str(e)}")
@router.post("/{orderid}/deliveryman/complete", response_model=ResponseModel)
async def deliveryman_complete_order(
background_tasks: BackgroundTasks,
orderid: str,
complete_data: OrderComplete,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_deliveryman_user)
):
"""完成订单"""
# 查询订单
order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.orderid == orderid,
ShippingOrderDB.deliveryman_user_id == current_user.userid
).first()
# 订单用户
order_user = db.query(UserDB).filter(
UserDB.userid == order.userid
).first()
if not order:
return error_response(code=404, message="订单不存在")
# 检查订单状态
if order.status != OrderStatus.DELIVERING:
return error_response(code=400, message="只有配送中的订单才能标记为完成")
try:
# 根据订单金额决定状态
if order.final_amount > 0:
order.status = OrderStatus.UNPAID # 需要支付
else:
order.status = OrderStatus.COMPLETED # 无需支付,直接完成
# 保存完成图片
if complete_data.images:
order.complete_images = ",".join(complete_data.images)
# 更新完成时间
order.completed_time = datetime.now()
# 使用账户管理器处理分账
if order.delivery_share > 0:
account_manager = AccountManager(db)
account_manager.change_balance(
user_id=order.deliveryman_user_id,
amount= order.delivery_share,
description=f"配送订单{order.orderid[-4:]}收益",
transaction_id=orderid
)
db.commit()
# 有邀请人,给邀请人积分奖励
if order_user.referral_code:
# 查询邀请人
invite_user = db.query(UserDB).filter(
UserDB.user_code == order_user.referral_code
).first()
if invite_user:
points = settings.FIRST_ORDER_REFERRAL_POINT if order.is_first_order else settings.COMMON_ORDER_REFERRAL_POINT
desc = f"蜜友首单奖励" if order.is_first_order else f"蜜友下单奖励"
# 邀请人赠送积分
point_manager = PointManager(db)
point_manager.add_points(
user_id=invite_user.userid,
points=points,
description=desc,
order_id=order.orderid
)
# 发送企业微信消息
wecom_bot = WecomBot()
order_info = OrderInfo.model_validate(order)
background_tasks.add_task(
wecom_bot.send_order_notification,
db,
order_info,
OrderStatus.COMPLETED
)
qcloud = QCloudManager()
background_tasks.add_task(
qcloud.send_sms_order_complete,
order.address_customer_phone
)
# 发送模板消息
if order.userid:
order_user = db.query(UserDB).filter(
UserDB.userid == order.userid
).first()
if order_user.mp_openid:
deliveryman_user = db.query(UserDB).filter(
UserDB.userid == order.deliveryman_user_id
).first()
data={
"character_string13": order.orderid,
"thing3": deliveryman_user.nickname,
"time5" : CommonUtils.get_current_time()
}
background_tasks.add_task(
sent_order_status_change_message,
openid=order_user.mp_openid,
template_id=settings.DELIVERY_ORDER_COMPLETED_TEMPLATE_ID,
data=data,
orderid=order.orderid
)
return success_response(
message="订单已完成" if order.final_amount == 0 else "请继续支付",
data=OrderInfo.model_validate(order)
)
except Exception as e:
db.rollback()
return error_response(code=500, message=f"操作失败: {str(e)}")
@router.post("/{orderid}/deliveryman/receive", response_model=ResponseModel)
async def deliveryman_receive_order(
background_tasks: BackgroundTasks,
orderid: str,
db: Session = Depends(get_db),
deliveryman: UserDB = Depends(get_deliveryman_user)
):
"""接单(仅配送员可用)"""
if not deliveryman.is_auth:
return error_response(code=400, message="请先完成实名认证")
# 查询订单
order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.orderid == orderid
).first()
if not order:
return error_response(code=404, message="订单不存在")
# 检查订单状态
if order.status != OrderStatus.CREATED:
return error_response(code=400, message="只能接待新创建的订单")
# 检查订单是否已被接单
if order.deliveryman_user_id is not None:
return error_response(code=400, message="订单已被其他配送员接单")
# 检查子订单是否全部处理
sub_orders = db.query(PointProductOrderDB).filter(
PointProductOrderDB.delivery_order_id == order.orderid
).all()
try:
# 更新订单状态和配送员ID
order.status = OrderStatus.RECEIVED
order.deliveryman_user_id = deliveryman.userid
order.received_time = datetime.now()
# 接单就确认收益
order.delivery_share = calculate_delivery_share(order, db)
db.commit()
# 发送企业微信消息
wecom_bot = WecomBot()
order_info = OrderInfo.model_validate(order)
background_tasks.add_task(
wecom_bot.send_order_notification,
db,
order_info,
OrderStatus.RECEIVED
)
# 发送模板消息
if order.userid:
order_user = db.query(UserDB).filter(
UserDB.userid == order.userid
).first()
if order_user.mp_openid:
deliveryman_user = db.query(UserDB).filter(
UserDB.userid == order.deliveryman_user_id
).first()
data={
"character_string9": order.orderid,
"time8": CommonUtils.get_current_time(),
"thing3": deliveryman_user.nickname
}
background_tasks.add_task(
sent_order_status_change_message,
openid=order_user.mp_openid,
template_id=settings.DELIVERY_ORDER_RECEIVED_TEMPLATE_ID,
data=data,
orderid=order.orderid
)
return success_response(
message="接单成功",
data=OrderInfo.model_validate(order)
)
except Exception as e:
db.rollback()
return error_response(code=500, message=f"接单失败: {str(e)}")
@router.post("/{orderid}/deliveryman/pickup", response_model=ResponseModel)
async def deliveryman_pickup_order(
orderid: str,
db: Session = Depends(get_db),
deliveryman: UserDB = Depends(get_deliveryman_user)
):
"""标记订单为已取货(仅配送员可用)"""
# 查询订单
order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.orderid == orderid,
ShippingOrderDB.deliveryman_user_id == deliveryman.userid # 必须是该配送员的订单
).first()
if not order:
return error_response(code=404, message="订单不存在")
# 检查订单状态
if order.status != OrderStatus.RECEIVED:
return error_response(code=400, message="只有已接单的订单才能标记为已取货")
# 检查子订单是否全部处理
sub_orders = db.query(PointProductOrderDB).filter(
PointProductOrderDB.delivery_order_id == order.orderid
).all()
for sub_order in sub_orders:
if sub_order.status != PointProductOrderStatus.PENDING:
return error_response(code=400, message="请先处理兑换商品子订单")
try:
# 更新订单状态为配送中
order.status = OrderStatus.DELIVERING
order.pickup_time = datetime.now()
db.commit()
return success_response(
message="已标记为取货",
data=OrderInfo.model_validate(order)
)
except Exception as e:
db.rollback()
return error_response(code=500, message=f"操作失败: {str(e)}")
@router.get("/platform/list", response_model=ResponseModel)
async def get_orders(
db: Session = Depends(get_db),
status: Optional[OrderStatus] = None,
user_id: Optional[int] = None,
order_id: Optional[str] = None,
skip: int = 0,
limit: int = 10):
"""获取订单列表"""
try:
# 构建基础查询
query = db.query(ShippingOrderDB)
# 添加用户ID过滤
if user_id:
query = query.filter(ShippingOrderDB.userid == user_id)
# 添加状态过滤
if status:
query = query.filter(ShippingOrderDB.status == status)
# 添加订单号过滤
if order_id:
query = query.filter(ShippingOrderDB.orderid == order_id)
# 获取总数
total = query.count()
# 分页查询
results = query.order_by(
ShippingOrderDB.create_time.desc()
).offset(skip).limit(limit).all()
orders = []
for order in results:
# 查询订单包裹信息
packages = db.query(
ShippingOrderPackageDB
).filter(
ShippingOrderPackageDB.orderid == order.orderid
).all()
# 格式化包裹信息
package_list = [{
"id": package.id,
"station_id": package.station_id,
"station_name": package.station_name,
"pickup_codes": package.pickup_codes
} for package in packages]
item = {
"orderid": order.orderid,
"userid": order.userid,
"status": order.status,
"pickup_images": order.optimized_pickup_images,
"package_count": order.package_count,
"pickup_code_count": order.pickup_code_count,
"pickup_images_count": order.pickup_images_count,
"create_time": order.create_time,
"delivery_method": order.delivery_method,
"original_amount": order.original_amount,
"delivery_date": order.delivery_date,
"time_period_name": order.time_period_name,
"coupon_discount_amount": order.coupon_discount_amount,
"point_discount_amount": order.point_discount_amount,
"cancel_reason": order.cancel_reason,
"additional_fee_amount": order.additional_fee_amount,
"is_delivery_cancel": order.cancel_user_id == order.deliveryman_user_id,
"complete_images": order.optimized_complete_images,
"completed_time": order.completed_time,
"final_amount": order.final_amount,
"is_first_order": order.is_first_order,
"packages": package_list,
"address": {
"name": order.address_customer_name,
"phone": order.address_customer_phone,
"gender": order.address_customer_gender,
"community_id": order.address_community_id,
"community_name": order.address_community_name,
"building_id": order.address_community_building_id,
"building_name": order.address_community_building_name,
"address_detail": order.address_detail
},
}
# 查询配送员
deliveryman = db.query(UserDB).filter(
UserDB.userid == order.deliveryman_user_id
).first()
if deliveryman:
item["deliveryman"] = {
"name": deliveryman.nickname,
"phone": deliveryman.phone
}
orders.append(item)
return success_response(data={
"total": total,
"items": orders
})
except Exception as e:
logging.exception(f"获取订单列表失败: {str(e)}")
return error_response(code=500, message=f"获取订单列表失败: {str(e)}")
@router.get("/admin/list", response_model=ResponseModel)
async def get_admin_orders(
status: Optional[OrderStatus] = None,
user_id: Optional[int] = None,
order_id: Optional[str] = None,
skip: int = 0,
limit: int = 20,
db: Session = Depends(get_db),
admin_user: UserDB = Depends(get_admin_user)
):
"""获取订单列表(管理员接口)
Args:
status: 订单状态过滤
user_id: 用户ID过滤
order_id: 订单号过滤
skip: 跳过记录数
limit: 返回记录数
"""
try:
# 构建基础查询
query = db.query(ShippingOrderDB)
# 添加用户ID过滤
if user_id:
query = query.filter(ShippingOrderDB.userid == user_id)
# 添加状态过滤
if status:
query = query.filter(ShippingOrderDB.status == status)
# 添加订单号过滤
if order_id:
query = query.filter(ShippingOrderDB.orderid == order_id)
# 获取总数
total = query.count()
# 分页查询
results = query.order_by(
ShippingOrderDB.create_time.desc()
).offset(skip).limit(limit).all()
orders = []
for order in results:
# 查询订单包裹信息
packages = db.query(
ShippingOrderPackageDB
).filter(
ShippingOrderPackageDB.orderid == order.orderid
).all()
# 格式化包裹信息
package_list = [{
"id": package.id,
"station_id": package.station_id,
"station_name": package.station_name,
"pickup_codes": package.pickup_codes
} for package in packages]
# 查询子订单
sub_orders = db.query(PointProductOrderDB).filter(
PointProductOrderDB.delivery_order_id == order.orderid
).all()
item = {
"orderid": order.orderid,
"userid": order.userid,
"status": order.status,
"pickup_images": order.optimized_pickup_images,
"package_count": order.package_count,
"pickup_code_count": order.pickup_code_count,
"pickup_images_count": order.pickup_images_count,
"create_time": order.create_time,
"delivery_method": order.delivery_method,
"original_amount": order.original_amount,
"coupon_discount_amount": order.coupon_discount_amount,
"point_discount_amount": order.point_discount_amount,
"complete_images": order.optimized_complete_images,
"completed_time": order.completed_time,
"final_amount": order.final_amount,
"packages": package_list,
"sub_orders": [PointProductOrderInfo.model_validate(sub_order) for sub_order in sub_orders],
"address": {
"name": order.address_customer_name,
"phone": order.address_customer_phone,
"gender": order.address_customer_gender,
"community_id": order.address_community_id,
"community_name": order.address_community_name,
"building_id": order.address_community_building_id,
"building_name": order.address_community_building_name,
"address_detail": order.address_detail
},
}
# 查询配送员
deliveryman = db.query(UserDB).filter(
UserDB.userid == order.deliveryman_user_id
).first()
if deliveryman:
item["deliveryman"] = {
"name": deliveryman.nickname,
"phone": deliveryman.phone
}
orders.append(item)
return success_response(data={
"total": total,
"items": orders
})
except Exception as e:
logging.exception(f"获取订单列表失败: {str(e)}")
return error_response(code=500, message=f"获取订单列表失败: {str(e)}")
# 获取配送员订单数量汇总
@router.get("/deliveryman/summary", response_model=ResponseModel)
async def deliveryman_order_summary(
db: Session = Depends(get_db),
deliveryman: UserDB = Depends(get_deliveryman_user)
):
"""获取配送员订单数量汇总"""
# 查询配送员总订单数量
total = db.query(ShippingOrderDB).filter(
ShippingOrderDB.deliveryman_user_id == deliveryman.userid,
ShippingOrderDB.status == OrderStatus.COMPLETED
).count()
today = datetime.now().date()
yesterday = today - timedelta(days=1)
today_start = datetime.combine(today, datetime.min.time())
today_end = datetime.combine(today, datetime.max.time())
yesterday_start = datetime.combine(yesterday, datetime.min.time())
yesterday_end = datetime.combine(yesterday, datetime.max.time())
# 查询配送员昨日、今日订单数量
yesterday_total = db.query(ShippingOrderDB).filter(
ShippingOrderDB.deliveryman_user_id == deliveryman.userid,
ShippingOrderDB.status == OrderStatus.COMPLETED,
ShippingOrderDB.completed_time.between(yesterday_start, yesterday_end)
).count()
today_total = db.query(ShippingOrderDB).filter(
ShippingOrderDB.deliveryman_user_id == deliveryman.userid,
ShippingOrderDB.status == OrderStatus.COMPLETED,
ShippingOrderDB.completed_time.between(today_start, today_end)
).count()
return success_response(data={
"total_count": total,
"yesterday_count": yesterday_total,
"today_count": today_total
})
@router.get("/deliveryman/check_new_order", response_model=ResponseModel)
async def deliveryman_check_new_orders(
db: Session = Depends(get_db),
deliveryman: UserDB = Depends(get_deliveryman_user)
):
"""检查新订单"""
# 从Redis获取新订单ID列表
order_ids = redis_client.pop_new_orders_from_queue(deliveryman.userid)
if not order_ids:
return success_response(data={
"has_new_order": False,
"order_ids": []
})
else:
return success_response(data={
"has_new_order": len(order_ids) > 0,
"order_ids": order_ids
})