增加 企业微信通知。

This commit is contained in:
aaron 2025-02-24 11:19:38 +08:00
parent d5fac2687a
commit 5fc85eaa39
5 changed files with 88 additions and 53 deletions

View File

@ -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(

View File

@ -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"): # 商家商品订单

View File

@ -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 项目"

View File

@ -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

View File

@ -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 # 距离,单位:米