增加 企业微信通知。
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 app.core.point_manager import PointManager
|
||||||
from datetime import time
|
from datetime import time
|
||||||
from app.core.wecombot import WecomBot
|
from app.core.wecombot import WecomBot
|
||||||
|
from app.models.config import ConfigDB
|
||||||
|
|
||||||
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:
|
||||||
@ -271,8 +273,9 @@ async def create_order(
|
|||||||
).all()
|
).all()
|
||||||
|
|
||||||
# 发送企业微信消息
|
# 发送企业微信消息
|
||||||
wecom_bot = WecomBot(settings.WECOM_WEBHOOK_URL)
|
wecom_bot = WecomBot()
|
||||||
wecom_bot.send_order_notification(db_order, OrderStatus.CREATED)
|
await wecom_bot.send_order_notification(db, db_order, OrderStatus.CREATED)
|
||||||
|
|
||||||
|
|
||||||
#发送订单创建成功的消息
|
#发送订单创建成功的消息
|
||||||
if current_user.mp_openid:
|
if current_user.mp_openid:
|
||||||
@ -679,6 +682,10 @@ async def cancel_order(
|
|||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
# 发送企业微信消息
|
||||||
|
wecom_bot = WecomBot()
|
||||||
|
await wecom_bot.send_order_notification(db, order, OrderStatus.CANCELLED)
|
||||||
|
|
||||||
# 发送模板消息
|
# 发送模板消息
|
||||||
if current_user.mp_openid:
|
if current_user.mp_openid:
|
||||||
await mp_client.send_template_message(
|
await mp_client.send_template_message(
|
||||||
@ -876,6 +883,10 @@ async def deliveryman_cancel_order(
|
|||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
# 发送企业微信消息
|
||||||
|
wecom_bot = WecomBot()
|
||||||
|
await wecom_bot.send_order_notification(db, order, OrderStatus.CANCELLED)
|
||||||
|
|
||||||
# 发送模板消息
|
# 发送模板消息
|
||||||
if order.userid:
|
if order.userid:
|
||||||
order_user = db.query(UserDB).filter(
|
order_user = db.query(UserDB).filter(
|
||||||
@ -952,6 +963,10 @@ async def complete_order(
|
|||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
# 发送企业微信消息
|
||||||
|
wecom_bot = WecomBot()
|
||||||
|
await wecom_bot.send_order_notification(db, order, OrderStatus.COMPLETED)
|
||||||
|
|
||||||
# 发送模板消息
|
# 发送模板消息
|
||||||
if order.userid:
|
if order.userid:
|
||||||
order_user = db.query(UserDB).filter(
|
order_user = db.query(UserDB).filter(
|
||||||
@ -1020,6 +1035,10 @@ async def receive_order(
|
|||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
# 发送企业微信消息
|
||||||
|
wecom_bot = WecomBot()
|
||||||
|
await wecom_bot.send_order_notification(db, order, OrderStatus.RECEIVED)
|
||||||
|
|
||||||
# 发送模板消息
|
# 发送模板消息
|
||||||
if order.userid:
|
if order.userid:
|
||||||
order_user = db.query(UserDB).filter(
|
order_user = db.query(UserDB).filter(
|
||||||
|
|||||||
@ -229,28 +229,6 @@ async def payment_notify(
|
|||||||
order.transaction_id = transaction_id
|
order.transaction_id = transaction_id
|
||||||
order.pay_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
|
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"): # 商家商品订单
|
elif out_trade_no.startswith("M"): # 商家商品订单
|
||||||
# 查询商户订单
|
# 查询商户订单
|
||||||
|
|||||||
@ -5,11 +5,16 @@ from datetime import datetime
|
|||||||
from app.core.utils import CommonUtils
|
from app.core.utils import CommonUtils
|
||||||
from app.models.order import OrderStatus
|
from app.models.order import OrderStatus
|
||||||
from app.models.order import ShippingOrderDB
|
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:
|
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
|
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:
|
if mentioned_mobile_list:
|
||||||
data["text"]["mentioned_mobile_list"] = 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消息
|
发送markdown消息
|
||||||
|
|
||||||
@ -60,9 +65,9 @@ class WecomBot:
|
|||||||
"content": content
|
"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
|
"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
|
"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",
|
"msgtype": "template_card",
|
||||||
"template_card": 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:
|
try:
|
||||||
headers = {'Content-Type': 'application/json'}
|
headers = {'Content-Type': 'application/json'}
|
||||||
response = requests.post(
|
|
||||||
self.webhook_url,
|
async with aiohttp.ClientSession() as session:
|
||||||
headers=headers,
|
async with session.post(
|
||||||
data=json.dumps(data)
|
webhook_url or self.webhook_url,
|
||||||
)
|
headers=headers,
|
||||||
result = response.json()
|
data=json.dumps(data)
|
||||||
|
) as response:
|
||||||
|
result = await response.json()
|
||||||
|
|
||||||
if result.get('errcode') == 0:
|
if result.get('errcode') == 0:
|
||||||
return True
|
return True
|
||||||
@ -145,7 +152,7 @@ class WecomBot:
|
|||||||
print(f"发送异常: {str(e)}")
|
print(f"发送异常: {str(e)}")
|
||||||
return False
|
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:
|
Returns:
|
||||||
bool: 是否发送成功
|
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:
|
try:
|
||||||
if notify_type == OrderStatus.CREATED:
|
if notify_type == OrderStatus.CREATED:
|
||||||
title = "🆕 新订单通知"
|
title = "🆕 新订单通知"
|
||||||
color = "green"
|
color = "green"
|
||||||
|
elif notify_type == OrderStatus.RECEIVED:
|
||||||
|
title = "🚚 已接单通知"
|
||||||
|
color = "blue"
|
||||||
elif notify_type == OrderStatus.COMPLETED:
|
elif notify_type == OrderStatus.COMPLETED:
|
||||||
title = "✅ 订单完成通知"
|
title = "✅ 配送完成通知"
|
||||||
color = "blue"
|
color = "blue"
|
||||||
elif notify_type == OrderStatus.CANCELLED:
|
elif notify_type == OrderStatus.CANCELLED:
|
||||||
title = "❌ 订单取消通知"
|
title = "❌ 订单取消通知"
|
||||||
@ -175,17 +204,23 @@ class WecomBot:
|
|||||||
> 下单时间: {CommonUtils.get_asia_datetime(shipping_order.create_time)}
|
> 下单时间: {CommonUtils.get_asia_datetime(shipping_order.create_time)}
|
||||||
> 包裹数量: {shipping_order.package_count}个
|
> 包裹数量: {shipping_order.package_count}个
|
||||||
> 订单金额: ¥{shipping_order.original_amount}
|
> 订单金额: ¥{shipping_order.original_amount}
|
||||||
> 积分抵扣: ¥{shipping_order.point_discount_amount}
|
|
||||||
> 实付金额: ¥{shipping_order.final_amount}
|
> 实付金额: ¥{shipping_order.final_amount}
|
||||||
> 配送方式: {shipping_order.delivery_method}
|
|
||||||
|
|
||||||
**收件信息**
|
**收件信息**
|
||||||
> 姓名: {shipping_order.address_customer_name}
|
> 姓名: {shipping_order.address_customer_name}
|
||||||
> 电话: {shipping_order.address_customer_phone}
|
> 电话: {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}
|
> 地址: {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:
|
except Exception as e:
|
||||||
print(f"发送订单通知异常: {str(e)}")
|
logging.exception(f"发送企业微信消息失败: {str(e)}")
|
||||||
return False
|
raise e
|
||||||
@ -20,6 +20,7 @@ class CommunityDB(Base):
|
|||||||
latitude = Column(DECIMAL(9,6), nullable=False) # 纬度,精确到小数点后6位
|
latitude = Column(DECIMAL(9,6), nullable=False) # 纬度,精确到小数点后6位
|
||||||
status = Column(Enum(CommunityStatus), nullable=False, default=CommunityStatus.UNOPEN)
|
status = Column(Enum(CommunityStatus), nullable=False, default=CommunityStatus.UNOPEN)
|
||||||
qy_group_qrcode = Column(String(200), nullable=True) # 企业微信群二维码地址
|
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())
|
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
update_time = Column(DateTime(timezone=True), onupdate=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)
|
latitude: float = Field(..., ge=-90, le=90)
|
||||||
status: CommunityStatus = Field(default=CommunityStatus.UNOPEN)
|
status: CommunityStatus = Field(default=CommunityStatus.UNOPEN)
|
||||||
qy_group_qrcode: Optional[str] = Field(None, max_length=200)
|
qy_group_qrcode: Optional[str] = Field(None, max_length=200)
|
||||||
|
webot_webhook: Optional[str] = Field(None, max_length=200)
|
||||||
|
|
||||||
class CommunityUpdate(BaseModel):
|
class CommunityUpdate(BaseModel):
|
||||||
name: Optional[str] = Field(None, max_length=100)
|
name: Optional[str] = Field(None, max_length=100)
|
||||||
@ -45,7 +47,7 @@ class CommunityUpdate(BaseModel):
|
|||||||
latitude: Optional[float] = Field(None, ge=-90, le=90)
|
latitude: Optional[float] = Field(None, ge=-90, le=90)
|
||||||
status: Optional[CommunityStatus] = None
|
status: Optional[CommunityStatus] = None
|
||||||
qy_group_qrcode: Optional[str] = Field(None, max_length=200)
|
qy_group_qrcode: Optional[str] = Field(None, max_length=200)
|
||||||
|
webot_webhook: Optional[str] = Field(None, max_length=200)
|
||||||
class CommunityInfo(BaseModel):
|
class CommunityInfo(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
name: str
|
name: str
|
||||||
@ -54,6 +56,7 @@ class CommunityInfo(BaseModel):
|
|||||||
longitude: float
|
longitude: float
|
||||||
status: CommunityStatus
|
status: CommunityStatus
|
||||||
qy_group_qrcode: Optional[str] = None
|
qy_group_qrcode: Optional[str] = None
|
||||||
|
webot_webhook: Optional[str] = None
|
||||||
optimized_qy_group_qrcode: Optional[str] = None
|
optimized_qy_group_qrcode: Optional[str] = None
|
||||||
distance: Optional[float] = None # 距离,单位:米
|
distance: Optional[float] = None # 距离,单位:米
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user