增加 企业微信通知。
This commit is contained in:
parent
d5fac2687a
commit
5fc85eaa39
@ -38,6 +38,8 @@ 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
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def calculate_price(price_request: OrderPriceCalculateRequest,user: UserDB,db: Session) -> OrderPriceResult:
|
||||
@ -271,9 +273,10 @@ async def create_order(
|
||||
).all()
|
||||
|
||||
# 发送企业微信消息
|
||||
wecom_bot = WecomBot(settings.WECOM_WEBHOOK_URL)
|
||||
wecom_bot.send_order_notification(db_order, OrderStatus.CREATED)
|
||||
wecom_bot = WecomBot()
|
||||
await wecom_bot.send_order_notification(db, db_order, OrderStatus.CREATED)
|
||||
|
||||
|
||||
#发送订单创建成功的消息
|
||||
if current_user.mp_openid:
|
||||
await mp_client.send_template_message(
|
||||
@ -679,6 +682,10 @@ async def cancel_order(
|
||||
|
||||
db.commit()
|
||||
|
||||
# 发送企业微信消息
|
||||
wecom_bot = WecomBot()
|
||||
await wecom_bot.send_order_notification(db, order, OrderStatus.CANCELLED)
|
||||
|
||||
# 发送模板消息
|
||||
if current_user.mp_openid:
|
||||
await mp_client.send_template_message(
|
||||
@ -876,6 +883,10 @@ async def deliveryman_cancel_order(
|
||||
|
||||
db.commit()
|
||||
|
||||
# 发送企业微信消息
|
||||
wecom_bot = WecomBot()
|
||||
await wecom_bot.send_order_notification(db, order, OrderStatus.CANCELLED)
|
||||
|
||||
# 发送模板消息
|
||||
if order.userid:
|
||||
order_user = db.query(UserDB).filter(
|
||||
@ -952,6 +963,10 @@ async def complete_order(
|
||||
|
||||
db.commit()
|
||||
|
||||
# 发送企业微信消息
|
||||
wecom_bot = WecomBot()
|
||||
await wecom_bot.send_order_notification(db, order, OrderStatus.COMPLETED)
|
||||
|
||||
# 发送模板消息
|
||||
if order.userid:
|
||||
order_user = db.query(UserDB).filter(
|
||||
@ -1020,6 +1035,10 @@ async def receive_order(
|
||||
|
||||
db.commit()
|
||||
|
||||
# 发送企业微信消息
|
||||
wecom_bot = WecomBot()
|
||||
await wecom_bot.send_order_notification(db, order, OrderStatus.RECEIVED)
|
||||
|
||||
# 发送模板消息
|
||||
if order.userid:
|
||||
order_user = db.query(UserDB).filter(
|
||||
|
||||
@ -228,28 +228,6 @@ async def payment_notify(
|
||||
order.completed_time = datetime.now()
|
||||
order.transaction_id = transaction_id
|
||||
order.pay_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
|
||||
|
||||
# 计算配送员分账金额
|
||||
# if order.deliveryman_user_id:
|
||||
# deliveryman_user = db.query(UserDB).filter(
|
||||
# UserDB.userid == order.deliveryman_user_id
|
||||
# ).first()
|
||||
# if deliveryman_user:
|
||||
# deliveryman_share = order.final_amount * deliveryman_user.delivery_commission_rate / 100
|
||||
# else:
|
||||
# deliveryman_share = 0
|
||||
# else:
|
||||
# deliveryman_share = 0
|
||||
|
||||
# # 使用账户管理器处理分账
|
||||
# if deliveryman_share > 0:
|
||||
# account_manager = AccountManager(db)
|
||||
# account_manager.change_balance(
|
||||
# user_id=order.deliveryman_user_id,
|
||||
# amount=deliveryman_share,
|
||||
# description=f"配送订单结算",
|
||||
# transaction_id=order.orderid
|
||||
# )
|
||||
|
||||
|
||||
elif out_trade_no.startswith("M"): # 商家商品订单
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
class Settings(BaseSettings):
|
||||
class Settings(BaseSettings):
|
||||
DEBUG: bool = True # 开发模式标志
|
||||
API_V1_STR: str = "/api/v1"
|
||||
PROJECT_NAME: str = "FastAPI 项目"
|
||||
|
||||
@ -5,11 +5,16 @@ from datetime import datetime
|
||||
from app.core.utils import CommonUtils
|
||||
from app.models.order import OrderStatus
|
||||
from app.models.order import ShippingOrderDB
|
||||
import aiohttp
|
||||
from app.models.community import CommunityDB
|
||||
from app.models.user import UserDB
|
||||
from sqlalchemy.orm import Session
|
||||
import logging
|
||||
|
||||
class WecomBot:
|
||||
"""企业微信机器人工具类"""
|
||||
|
||||
def __init__(self, webhook_url: str):
|
||||
def __init__(self, webhook_url: str = None):
|
||||
"""
|
||||
初始化机器人
|
||||
|
||||
@ -18,7 +23,7 @@ class WecomBot:
|
||||
"""
|
||||
self.webhook_url = webhook_url
|
||||
|
||||
def send_text(self, content: str, mentioned_list: List[str] = None, mentioned_mobile_list: List[str] = None) -> bool:
|
||||
async def send_text(self, content: str, mentioned_list: List[str] = None, mentioned_mobile_list: List[str] = None, webhook_url: str = None) -> bool:
|
||||
"""
|
||||
发送文本消息
|
||||
|
||||
@ -42,9 +47,9 @@ class WecomBot:
|
||||
if mentioned_mobile_list:
|
||||
data["text"]["mentioned_mobile_list"] = mentioned_mobile_list
|
||||
|
||||
return self._send(data)
|
||||
return await self._send(data, webhook_url)
|
||||
|
||||
def send_markdown(self, content: str) -> bool:
|
||||
async def send_markdown(self, content: str, webhook_url: str = None) -> bool:
|
||||
"""
|
||||
发送markdown消息
|
||||
|
||||
@ -60,9 +65,9 @@ class WecomBot:
|
||||
"content": content
|
||||
}
|
||||
}
|
||||
return self._send(data)
|
||||
return await self._send(data, webhook_url)
|
||||
|
||||
def send_image(self, base64: str, md5: str) -> bool:
|
||||
async def send_image(self, base64: str, md5: str, webhook_url: str = None) -> bool:
|
||||
"""
|
||||
发送图片消息
|
||||
|
||||
@ -80,9 +85,9 @@ class WecomBot:
|
||||
"md5": md5
|
||||
}
|
||||
}
|
||||
return self._send(data)
|
||||
return await self._send(data)
|
||||
|
||||
def send_news(self, articles: List[Dict[str, str]]) -> bool:
|
||||
async def send_news(self, articles: List[Dict[str, str]], webhook_url: str = None) -> bool:
|
||||
"""
|
||||
发送图文消息
|
||||
|
||||
@ -98,9 +103,9 @@ class WecomBot:
|
||||
"articles": articles
|
||||
}
|
||||
}
|
||||
return self._send(data)
|
||||
return await self._send(data, webhook_url)
|
||||
|
||||
def send_template_card(self, template_card: Dict) -> bool:
|
||||
async def send_template_card(self, template_card: Dict, webhook_url: str = None) -> bool:
|
||||
"""
|
||||
发送模板卡片消息
|
||||
|
||||
@ -114,9 +119,9 @@ class WecomBot:
|
||||
"msgtype": "template_card",
|
||||
"template_card": template_card
|
||||
}
|
||||
return self._send(data)
|
||||
return await self._send(data)
|
||||
|
||||
def _send(self, data: Dict) -> bool:
|
||||
async def _send(self, data: Dict, webhook_url: str = None) -> bool:
|
||||
"""
|
||||
发送消息
|
||||
|
||||
@ -128,12 +133,14 @@ class WecomBot:
|
||||
"""
|
||||
try:
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
response = requests.post(
|
||||
self.webhook_url,
|
||||
headers=headers,
|
||||
data=json.dumps(data)
|
||||
)
|
||||
result = response.json()
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(
|
||||
webhook_url or self.webhook_url,
|
||||
headers=headers,
|
||||
data=json.dumps(data)
|
||||
) as response:
|
||||
result = await response.json()
|
||||
|
||||
if result.get('errcode') == 0:
|
||||
return True
|
||||
@ -145,7 +152,7 @@ class WecomBot:
|
||||
print(f"发送异常: {str(e)}")
|
||||
return False
|
||||
|
||||
def send_order_notification(self, shipping_order: ShippingOrderDB, notify_type: OrderStatus = OrderStatus.CREATED) -> bool:
|
||||
def send_order_notification(self,db: Session, shipping_order: ShippingOrderDB, notify_type: OrderStatus = OrderStatus.CREATED) -> bool:
|
||||
"""
|
||||
发送订单通知
|
||||
|
||||
@ -156,12 +163,34 @@ class WecomBot:
|
||||
Returns:
|
||||
bool: 是否发送成功
|
||||
"""
|
||||
|
||||
# 获取webhook
|
||||
webhook = None
|
||||
if shipping_order.address_community_id:
|
||||
community = db.query(CommunityDB).filter(
|
||||
CommunityDB.id == shipping_order.address_community_id
|
||||
).first()
|
||||
if community:
|
||||
webhook = community.webot_webhook
|
||||
|
||||
if not webhook:
|
||||
raise ValueError("不支持的通知类型")
|
||||
|
||||
deliveryman = None
|
||||
if shipping_order.deliveryman_user_id:
|
||||
deliveryman = db.query(UserDB).filter(
|
||||
UserDB.userid == shipping_order.deliveryman_user_id
|
||||
).first()
|
||||
|
||||
try:
|
||||
if notify_type == OrderStatus.CREATED:
|
||||
title = "🆕 新订单通知"
|
||||
color = "green"
|
||||
elif notify_type == OrderStatus.RECEIVED:
|
||||
title = "🚚 已接单通知"
|
||||
color = "blue"
|
||||
elif notify_type == OrderStatus.COMPLETED:
|
||||
title = "✅ 订单完成通知"
|
||||
title = "✅ 配送完成通知"
|
||||
color = "blue"
|
||||
elif notify_type == OrderStatus.CANCELLED:
|
||||
title = "❌ 订单取消通知"
|
||||
@ -175,17 +204,23 @@ class WecomBot:
|
||||
> 下单时间: {CommonUtils.get_asia_datetime(shipping_order.create_time)}
|
||||
> 包裹数量: {shipping_order.package_count}个
|
||||
> 订单金额: ¥{shipping_order.original_amount}
|
||||
> 积分抵扣: ¥{shipping_order.point_discount_amount}
|
||||
> 实付金额: ¥{shipping_order.final_amount}
|
||||
> 配送方式: {shipping_order.delivery_method}
|
||||
|
||||
**收件信息**
|
||||
> 姓名: {shipping_order.address_customer_name}
|
||||
> 电话: {shipping_order.address_customer_phone}
|
||||
> 地址: {shipping_order.address_community_name} | {shipping_order.address_community_building_name} {shipping_order.address_detail}
|
||||
> 电话: {shipping_order.address_customer_phone[:3]}\*\*\*\*{shipping_order.address_customer_phone[7:]}
|
||||
> 地址: {shipping_order.address_community_name} | {shipping_order.address_community_building_name} {shipping_order.address_detail[0:3]} \*\*\*\*
|
||||
"""
|
||||
return self.send_markdown(content)
|
||||
|
||||
if shipping_order.deliveryman_user_id:
|
||||
content += f"""
|
||||
**配送员信息**
|
||||
> 姓名: {deliveryman.nickname}
|
||||
> 电话: {deliveryman.phone[:3]}\*\*\*\*{deliveryman.phone[7:]}
|
||||
"""
|
||||
|
||||
return self.send_markdown(content, webhook)
|
||||
|
||||
except Exception as e:
|
||||
print(f"发送订单通知异常: {str(e)}")
|
||||
return False
|
||||
logging.exception(f"发送企业微信消息失败: {str(e)}")
|
||||
raise e
|
||||
@ -20,6 +20,7 @@ class CommunityDB(Base):
|
||||
latitude = Column(DECIMAL(9,6), nullable=False) # 纬度,精确到小数点后6位
|
||||
status = Column(Enum(CommunityStatus), nullable=False, default=CommunityStatus.UNOPEN)
|
||||
qy_group_qrcode = Column(String(200), nullable=True) # 企业微信群二维码地址
|
||||
webot_webhook = Column(String(200), nullable=True) # 企业微信机器人webhook
|
||||
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
@ -37,6 +38,7 @@ class CommunityCreate(BaseModel):
|
||||
latitude: float = Field(..., ge=-90, le=90)
|
||||
status: CommunityStatus = Field(default=CommunityStatus.UNOPEN)
|
||||
qy_group_qrcode: Optional[str] = Field(None, max_length=200)
|
||||
webot_webhook: Optional[str] = Field(None, max_length=200)
|
||||
|
||||
class CommunityUpdate(BaseModel):
|
||||
name: Optional[str] = Field(None, max_length=100)
|
||||
@ -45,7 +47,7 @@ class CommunityUpdate(BaseModel):
|
||||
latitude: Optional[float] = Field(None, ge=-90, le=90)
|
||||
status: Optional[CommunityStatus] = None
|
||||
qy_group_qrcode: Optional[str] = Field(None, max_length=200)
|
||||
|
||||
webot_webhook: Optional[str] = Field(None, max_length=200)
|
||||
class CommunityInfo(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
@ -54,6 +56,7 @@ class CommunityInfo(BaseModel):
|
||||
longitude: float
|
||||
status: CommunityStatus
|
||||
qy_group_qrcode: Optional[str] = None
|
||||
webot_webhook: Optional[str] = None
|
||||
optimized_qy_group_qrcode: Optional[str] = None
|
||||
distance: Optional[float] = None # 距离,单位:米
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user