This commit is contained in:
aaron 2025-03-04 22:13:51 +08:00
parent f95c71c137
commit c915f4ffe4
5 changed files with 88 additions and 24 deletions

View File

@ -17,6 +17,7 @@ from app.models.community import CommunityDB, CommunityInfo
from typing import List, Optional from typing import List, Optional
import logging import logging
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from app.core.redis_client import redis_client
router = APIRouter() router = APIRouter()
@ -120,12 +121,17 @@ async def get_community_time_periods(
result = [] result = []
for ctp in community_time_periods: for ctp in community_time_periods:
# 获取今日订单数量
today_orders_count = redis_client.get_community_period_today_orders_count(ctp.CommunityTimePeriodDB.id)
result.append({ result.append({
"time_period_id": ctp.CommunityTimePeriodDB.time_period_id, "time_period_id": ctp.CommunityTimePeriodDB.time_period_id,
"time_period_name": ctp.time_period_name, "time_period_name": ctp.time_period_name,
"capacity": ctp.CommunityTimePeriodDB.capacity, "capacity": ctp.CommunityTimePeriodDB.capacity,
"from_time": ctp.time_period_from_time, "from_time": ctp.time_period_from_time,
"to_time": ctp.time_period_to_time "to_time": ctp.time_period_to_time,
"order_full": today_orders_count >= ctp.CommunityTimePeriodDB.capacity,
"order_busy": today_orders_count >= ctp.CommunityTimePeriodDB.capacity * 0.8
}) })
return success_response(data=result) return success_response(data=result)

View File

@ -43,7 +43,7 @@ from app.core.mpmessage import sent_order_status_change_message
from fastapi import BackgroundTasks from fastapi import BackgroundTasks
from app.core.coupon_manager import CouponManager from app.core.coupon_manager import CouponManager
from app.core.redis_client import redis_client from app.core.redis_client import redis_client
from app.models.timeperiod import TimePeriodDB
router = APIRouter() router = APIRouter()
def calculate_price(price_request: OrderPriceCalculateRequest,user: UserDB,db: Session) -> OrderPriceResult: def calculate_price(price_request: OrderPriceCalculateRequest,user: UserDB,db: Session) -> OrderPriceResult:
@ -241,6 +241,19 @@ async def create_order(
delivery_method=order.delivery_method, delivery_method=order.delivery_method,
is_first_order=is_first_order is_first_order=is_first_order
) )
# 获取社区配送时段
time_period = db.query(TimePeriodDB).filter(
TimePeriodDB.id == order.time_period_id
).first()
if time_period:
db_order.time_period_id = time_period.id
db_order.time_period_name = time_period.name
db_order.time_period_from_time = time_period.from_time
db_order.time_period_to_time = time_period.to_time
# 获取取件图片
if order.price_request.pickup_images: if order.price_request.pickup_images:
db_order.pickup_images = order.price_request.pickup_images db_order.pickup_images = order.price_request.pickup_images
@ -308,7 +321,7 @@ async def create_order(
OrderStatus.CREATED OrderStatus.CREATED
) )
#发送订单创建成功的消息 #发送订单创建成功的公众号消息
if current_user.mp_openid: if current_user.mp_openid:
data={ data={
"character_string13": db_order.orderid, "character_string13": db_order.orderid,
@ -326,12 +339,6 @@ async def create_order(
orderid=db_order.orderid orderid=db_order.orderid
) )
# 超过晚上8点则使用明天送达的文案
if datetime.now() > datetime.now().replace(hour=settings.ORDER_SPLIT_TIME_HOUR, minute=0, second=0):
success_text = settings.ORDER_SUCCESS_TOMORROW_TEXT
else:
success_text = settings.ORDER_SUCCESS_TODAY_TEXT
# 添加到新订单队列 # 添加到新订单队列
if db_order.address_community_id: if db_order.address_community_id:
background_tasks.add_task( background_tasks.add_task(
@ -341,12 +348,19 @@ async def create_order(
db db
) )
# 今日订单加入今日选中的配送时段的 Redis 消息队列
background_tasks.add_task(
redis_client.push_order_to_community_period_today_queue,
order.community_time_period_id,
db_order.orderid
)
return success_response( return success_response(
message="订单创建成功", message="订单创建成功",
data={ data={
"order": OrderInfo.model_validate(db_order), "order": OrderInfo.model_validate(db_order),
"packages": [OrderPackageInfo.model_validate(p) for p in packages], "packages": [OrderPackageInfo.model_validate(p) for p in packages],
"success_text" : success_text "success_text" : f"订单预计 {db_order.time_period_name} 送达,请注意查收"
} }
) )
except Exception as e: except Exception as e:
@ -421,6 +435,10 @@ async def get_order_detail(
# 计算配送时间 # 计算配送时间
delivery_time = "预计明日送达" if datetime.now() > datetime.now().replace(hour=settings.ORDER_SPLIT_TIME_HOUR, minute=0, second=0) else "预计今日送达" delivery_time = "预计明日送达" if datetime.now() > datetime.now().replace(hour=settings.ORDER_SPLIT_TIME_HOUR, minute=0, second=0) else "预计今日送达"
# 如果配送时段不为空,则使用配送时段的时间
if order.time_period_id:
delivery_time = f"{order.time_period_name} {order.time_period_from_time.strftime('%H:%M')} - {order.time_period_to_time.strftime('%H:%M')}"
# 构建响应数据 # 构建响应数据
order_data = { order_data = {
"orderid": order.orderid, "orderid": order.orderid,
@ -461,6 +479,12 @@ async def get_order_detail(
"community_id": order.address_community_id, "community_id": order.address_community_id,
"community_name": order.address_community_name, "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 "delivery_time": delivery_time
} }
@ -796,11 +820,6 @@ async def deliveryman_orders(
if OrderStatus.CREATED not in statuses: if OrderStatus.CREATED not in statuses:
query = query.filter(ShippingOrderDB.deliveryman_user_id == deliveryman.userid) query = query.filter(ShippingOrderDB.deliveryman_user_id == deliveryman.userid)
# 如果订单状态是待接单,则只显示小于等于 20 点的订单
if settings.ORDER_SPLIT_ENABLE:
if OrderStatus.CREATED in statuses:
query = query.filter(ShippingOrderDB.create_time <= datetime.now().replace(hour=settings.ORDER_SPLIT_TIME_HOUR, minute=0, second=0))
# 楼栋筛选 # 楼栋筛选
if building_id: if building_id:
query = query.filter(ShippingOrderDB.address_community_building_id == building_id) query = query.filter(ShippingOrderDB.address_community_building_id == building_id)

View File

@ -22,12 +22,6 @@ class Settings(BaseSettings):
ORDER_EXTRA_PACKAGE_PRICE: float = 0.5 # 额外包裹费用 ORDER_EXTRA_PACKAGE_PRICE: float = 0.5 # 额外包裹费用
ORDER_EXTRA_PACKAGE_THRESHOLD: int = 5 # 额外收费阈值 ORDER_EXTRA_PACKAGE_THRESHOLD: int = 5 # 额外收费阈值
#订单创建成功文案
ORDER_SPLIT_ENABLE: bool = False
ORDER_SPLIT_TIME_HOUR: int = 20 # 订单分割时间
ORDER_SUCCESS_TODAY_TEXT: str = "订单预计今晚前送达,请注意查收"
ORDER_SUCCESS_TOMORROW_TEXT: str = "订单预计明晚前送达,请注意查收"
# 邀请新人赠送优惠券ID # 邀请新人赠送优惠券ID
FIRST_ORDER_REFERRAL_COUPON_ID: int = 1 FIRST_ORDER_REFERRAL_COUPON_ID: int = 1
FIRST_ORDER_REFERRAL_COUPON_COUNT: int = 1 FIRST_ORDER_REFERRAL_COUPON_COUNT: int = 1

View File

@ -5,6 +5,9 @@ from app.core.config import settings
from typing import List, Dict, Any, Optional from typing import List, Dict, Any, Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.models.user import UserDB from app.models.user import UserDB
from datetime import datetime
from app.models.user import UserRole
class RedisClient: class RedisClient:
"""Redis 客户端""" """Redis 客户端"""
@ -33,6 +36,36 @@ class RedisClient:
"""获取 Redis 客户端""" """获取 Redis 客户端"""
return self.client return self.client
def push_order_to_community_period_today_queue(self, community_time_period_id: int, order_id: str) -> bool:
"""
添加新订单到今日队列
"""
try:
today_date_str = datetime.now().strftime("%Y-%m-%d")
key = f"community_period:{community_time_period_id}:today_orders:{today_date_str}"
self.client.lpush(key, order_id)
# 设置过期时间为24小时
self.client.expire(key, 86400)
return True
except Exception as e:
logging.error(f"添加新订单到今日队列失败: {str(e)}")
return False
def get_community_period_today_orders_count(self, community_time_period_id: int) -> int:
"""
获取今日队列中的订单数量
"""
try:
today_date_str = datetime.now().strftime("%Y-%m-%d")
key = f"community_period:{community_time_period_id}:today_orders:{today_date_str}"
return self.client.llen(key)
except Exception as e:
logging.error(f"获取今日队列中的订单数量失败: {str(e)}")
return 0
def push_order_to_queue(self, community_id: int, order_id: str, db: Session) -> bool: def push_order_to_queue(self, community_id: int, order_id: str, db: Session) -> bool:
""" """
添加新订单到社区队列 添加新订单到社区队列
@ -47,7 +80,7 @@ class RedisClient:
""" """
try: try:
# 查询所有社区的用户 # 查询所有社区的用户
users = db.query(UserDB).filter(UserDB.community_id == community_id).all() users = db.query(UserDB).filter(UserDB.community_id == community_id, UserDB.roles == UserRole.DELIVERYMAN).all()
for user in users: for user in users:
key = f"user:{user.userid}:community:{community_id}:new_orders" key = f"user:{user.userid}:community:{community_id}:new_orders"
# 使用 LPUSH 将订单ID添加到列表头部 # 使用 LPUSH 将订单ID添加到列表头部

View File

@ -1,13 +1,13 @@
from datetime import datetime from datetime import datetime
from typing import Optional, List from typing import Optional, List
from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum, Boolean from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum, Boolean, Time
from sqlalchemy.sql import func from sqlalchemy.sql import func
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from .database import Base from .database import Base
import enum import enum
from app.models.user import Gender from app.models.user import Gender
from app.core.imageprocessor import process_image, ImageFormat from app.core.imageprocessor import process_image, ImageFormat
from datetime import time
class OrderStatus(str, enum.Enum): class OrderStatus(str, enum.Enum):
CREATED = "CREATED" # 已创建 CREATED = "CREATED" # 已创建
CANCELLED = "CANCELLED" # 已取消 CANCELLED = "CANCELLED" # 已取消
@ -40,6 +40,11 @@ class ShippingOrderDB(Base):
orderid = Column(String(32), primary_key=True) orderid = Column(String(32), primary_key=True)
userid = Column(Integer, ForeignKey("users.userid"), index=True) userid = Column(Integer, ForeignKey("users.userid"), index=True)
# 配送时段ID
time_period_id = Column(Integer, nullable=False, default=0)
time_period_name = Column(String(50), nullable=False, default='')
time_period_from_time = Column(Time, nullable=False, default=time(0, 0, 0))
time_period_to_time = Column(Time, nullable=False, default=time(0, 0, 0))
# 配送地址信息 # 配送地址信息
address_customer_name = Column(String(50), nullable=False, default='') # 客户名称快照 address_customer_name = Column(String(50), nullable=False, default='') # 客户名称快照
@ -120,6 +125,8 @@ class OrderPriceCalculateRequest(BaseModel):
class OrderCreate(BaseModel): class OrderCreate(BaseModel):
addressid: int addressid: int
price_request: OrderPriceCalculateRequest price_request: OrderPriceCalculateRequest
community_time_period_id: int = 0
time_period_id: int = 0
delivery_method: DeliveryMethod = Field( delivery_method: DeliveryMethod = Field(
default=DeliveryMethod.DELIVERY_AT_DOORSTEP, default=DeliveryMethod.DELIVERY_AT_DOORSTEP,
description="配送方式:放在门口或投递到家" description="配送方式:放在门口或投递到家"
@ -129,6 +136,11 @@ class OrderInfo(BaseModel):
orderid: str orderid: str
userid: int userid: int
time_period_id: int
time_period_name: str
time_period_from_time: time
time_period_to_time: time
address_customer_name: str address_customer_name: str
address_customer_phone: str address_customer_phone: str
address_community_id: int address_community_id: int