@@ -0,0 +1,294 @@
# app/api/wechat.py
from fastapi import APIRouter , Query , BackgroundTasks , Depends
from tortoise . expressions import Q
from app . controllers . weixin . utils import get_buyer_nick_from_group_name
from app . controllers . weixin . group import weixin_group_chat_controller
from app . controllers . weixin . customer import weixin_customer_controller
from app . controllers . weixin . user import weixin_user_controller
from app . controllers . action import action_controller
from app . schemas . weixin import WeixinUserBindInfo , WeixinOrderBindInfo , TriggerWeixinGroupChat , WeixinOrderRemark , WeixinCustomerFilter , WeixinCustomerCreate
from app . http_base import unified_resp
from app . schemas . apis import Paginate
from . base import get_weixin_user
from . base import WeixinUserDep
from app . models . msg import ActionType
from datetime import datetime , timedelta
from app . utils . event_task import event_manager , EventType
from app . core . cache import cache_if
# from app.schemas.crm import CrmBindInfoCreate, CrmBindInfoUpdate
import logging
logger = logging . getLogger ( __name__ )
router = APIRouter ( prefix = " " )
# 废弃
@router.post ( " /list_user_join_group " , summary = " 加载用户加入的群聊列表 " )
@unified_resp
async def list_user_join_group ( customer : WeixinCustomerCreate , weixin_user : dict = Depends ( get_weixin_user ) ) :
print ( f ' list_user_join_group, customer: { customer } ' )
# user_join_group = await weixin_group_chat_controller.list_user_join_group(customer.xingyun_id)
user_join_group = await weixin_customer_controller . get_user_detail ( customer . weixin_id )
return user_join_group
@router.get ( " /list_customer " , summary = " 加载客户列表 " )
@unified_resp
async def list_msg ( paginate : Paginate = Depends ( ) , order : str = " -id " , customer_filter : WeixinCustomerFilter = Depends ( ) , weixin_user : dict = Depends ( get_weixin_user ) ) :
print ( ' paginate ' , paginate . page , paginate . page_size )
print ( ' customer_filter ' , customer_filter )
print ( ' weixin_user ' , weixin_user . username , weixin_user . userid )
q = Q ( )
data = { }
if customer_filter . order_id is not None :
q & = Q ( order_id = customer_filter . order_id )
data [ ' order_id ' ] = customer_filter . order_id
if customer_filter . shop_name is not None :
q & = Q ( shop_name__contains = customer_filter . shop_name )
data [ ' shop_name ' ] = customer_filter . shop_name
if customer_filter . union_id is not None :
# 是或者的关系 weixin_id\xingyun_id\taobao_id\union_id
q & = ( Q ( weixin_id = customer_filter . union_id ) | Q ( xingyun_id = customer_filter . union_id ) | Q ( taobao_id = customer_filter . union_id ) | Q ( union_id = customer_filter . union_id ) )
data [ ' union_id ' ] = customer_filter . union_id
if customer_filter . union_name is not None :
# 是或者的关系 weixin_username\xingyun_name\taobao_name
q & = ( Q ( weixin_name__contains = customer_filter . union_name ) | Q ( xingyun_name__contains = customer_filter . union_name ) | Q ( taobao_name__contains = customer_filter . union_name ) )
data [ ' union_name ' ] = customer_filter . union_name
if customer_filter . xingyun_tags is not None :
q & = Q ( xingyun_tags__contains = { " tagName " : customer_filter . xingyun_tags } )
data [ ' xingyun_tags ' ] = customer_filter . xingyun_tags
if customer_filter . has_order is not None :
q & = Q ( order_id__isnull = not customer_filter . has_order )
data [ ' has_order ' ] = customer_filter . has_order
# 打印查询条件明文
print ( ' raw query ' , data )
total , user_list = await weixin_customer_controller . list ( paginate . page , paginate . page_size , order = [ order ] , search = q )
lists = [ ]
for user in user_list :
user_info = user . dump_dict ( )
lists . append ( user_info )
user_info [ ' user_join_group ' ] = await weixin_customer_controller . get_user_detail ( user . weixin_id )
return { " count " : total , " lists " : lists }
# 群聊入口
@router.get ( " /get_user_info " , summary = " 通过群ID获取到群信息以及同步数据到本地 " )
@unified_resp
async def get_external_group_chat_info ( userid : str ) :
weixin_user = await weixin_user_controller . model . filter ( userid = userid ) . first ( )
return weixin_user . to_dict ( )
# 群聊入口
@router.get ( " /group/get_external_group_chat_info " , summary = " 通过群ID获取到群信息以及同步数据到本地 " )
@unified_resp
async def get_external_group_chat_info ( chat_id : str , background_tasks : BackgroundTasks ) :
group_info = await weixin_group_chat_controller . get_external_group_chat_info ( chat_id )
if group_info [ ' detect_update ' ] :
await event_manager . publish_async ( EventType . GROUP_CHAT_UPDATED , group_info , background_tasks )
return group_info
@router.get ( " /group/get_order_relative_user_list_by_weixin_groupid " , summary = " 通过群ID获取订单相关用户列表 " )
@unified_resp
async def get_order_relative_user_list_by_weixin_groupid ( chat_id : str = Query ( . . . , description = " 群ID " ) , background_tasks : BackgroundTasks = None ) :
async with cache_if ( f ' order:chat: { chat_id } ' , ttl = 60 * 3 ) as cache :
if cache . hit :
order_list = cache . value
if order_list :
order_list [ 0 ] = await weixin_group_chat_controller . get_user_detail_by_order ( order_id = order_list [ 0 ] [ ' ctid ' ] )
else :
order_list = await _get_order_relative_user_list_by_weixin_groupid ( chat_id , background_tasks )
cache . set ( order_list )
return order_list
async def _get_order_relative_user_list_by_weixin_groupid ( chat_id : str = Query ( . . . , description = " 群ID " ) , background_tasks : BackgroundTasks = None ) :
group_info = await weixin_group_chat_controller . get_external_group_chat_info ( chat_id )
logger . info ( f ' group_info: { group_info } ' )
if group_info [ ' detect_update ' ] or True :
await event_manager . publish_async ( EventType . GROUP_CHAT_UPDATED , group_info , background_tasks )
name = group_info . get ( ' name ' )
logger . debug ( f ' 群聊名称: { name } chat_id: { chat_id } ' )
user_order_list = [ ]
external_member_list = group_info [ ' external_member_list ' ]
if external_member_list :
userid_list = [ member [ ' userid ' ] for member in external_member_list if member . get ( ' userid ' ) ]
logger . debug ( f ' userid_list: { userid_list } ' )
customer_list = await weixin_customer_controller . model . filter ( weixin_id__in = userid_list , taobao_id__isnull = False ) . all ( )
for customer in customer_list :
buyer = customer . taobao_name or customer . taobao_id
if not buyer : continue
logger . debug ( f ' buyer: { buyer } ' )
result , order_list = await weixin_group_chat_controller . get_order_relative_user_list_by_weixin_userid ( customer . weixin_id )
if not result : continue
user_order_list = order_list
break
# return await weixin_group_chat_controller.get_order_relative_user_list_by_weixin_group_name(buyer_nick)
# return await weixin_group_chat_controller.get_order_relative_user_list_by_weixin_group_buyer_id(buyer_id)
if not user_order_list :
logger . warning ( f ' 群内成员没有订单,将根据群聊名称 { name } 来获取订单相关用户列表 ' )
assert name , " 当前群聊未命名 "
buyer_nick = get_buyer_nick_from_group_name ( name )
logger . debug ( f ' name: { name } ; buyer_nick: { buyer_nick } ' )
assert buyer_nick , " 当前群聊未命名 "
user_order_list = await weixin_group_chat_controller . get_order_relative_user_list_by_weixin_group_name ( buyer_nick )
if group_info [ ' detect_update ' ] :
try :
await action_controller . check_create_group_action_is_done ( group_info , user_order_list [ 0 ] [ ' shop_name ' ] if user_order_list else None )
except Exception as e :
logger . exception ( f ' 检查创建群聊动作是否完成失败: { e } ' )
return user_order_list
# @router.get("/group/load_xingyun_group_info", summary="通过群ID获取订单相关用户列表")
# @unified_resp
# async def load_xingyun_group_info():
# return await weixin_group_chat_controller.load_xingyun_group_info()
@router.get ( " /get_user_detail_by_order " , summary = " 通过订单ID获取订单相关用户详情 " )
@unified_resp
async def get_user_detail_by_order ( order_id : str ) :
return await weixin_group_chat_controller . get_user_detail_by_order ( order_id )
@router.get ( " /get_erp_order_log " , summary = " 通过订单ID获取订单日志 " )
@unified_resp
async def get_erp_order_log ( order_id : str , login_user : WeixinUserDep ) :
result = await weixin_group_chat_controller . get_erp_order_log ( order_id )
try :
await action_controller . new_action ( ActionType . VIEW_ERP_LOG , login_user , order_id = order_id )
except Exception as e :
logger . exception ( e )
logger . error ( f ' 员工操作日志记录失败 ' )
return result
# 通过私聊入口
@router.get ( " /get_order_relative_user_list_by_weixin_userid " , summary = " 通过用户ID获取订单相关用户列表 " )
@unified_resp
async def get_order_relative_user_list_by_weixin_userid ( userid : str , background_tasks : BackgroundTasks ) :
result , order_list = await weixin_group_chat_controller . get_order_relative_user_list_by_weixin_userid ( userid )
if not result :
await event_manager . publish_async ( EventType . OPEN_PERSONAL_CHAT , { " userid " : userid } , background_tasks )
return order_list
@router.post ( " /bind_order " , summary = " 绑定订单 " )
@unified_resp
async def bind_order ( bind_in : WeixinOrderBindInfo , background_tasks : BackgroundTasks , login_user : WeixinUserDep ) :
bind_in . userid = bind_in . userid . strip ( )
bind_in . order_id = bind_in . order_id . strip ( )
logger . info ( f ' 【绑定订单】userid: { bind_in . userid } ; order_id: { bind_in . order_id } ' )
old_info = await weixin_customer_controller . model . filter ( weixin_id = bind_in . userid , order_id = bind_in . order_id ) . first ( )
assert not old_info , " 不用为客户绑定相同订单 "
result , orders = await weixin_customer_controller . bind_order ( bind_in )
try :
await action_controller . new_action ( ActionType . BIND_ORDER , login_user , * * bind_in . model_dump ( exclude_unset = True ) )
if orders and bind_in . remark :
orders = [ {
" title " : order . get ( " title " ) ,
" ctid " : order . get ( " ctid " ) ,
" trade_no " : order . get ( " trade_no " ) ,
" remark " : order . get ( " remark " , " " ) ,
} for order in orders ]
need_monitor_order_list = await weixin_customer_controller . remark_order_by_order_id ( remark = bind_in . remark , orders = orders )
await action_controller . new_action ( ActionType . WRITE_REMARK , login_user , order_id = bind_in . order_id , remark = bind_in . remark , orders = need_monitor_order_list , done = len ( need_monitor_order_list ) == 0 )
except Exception as e :
logger . exception ( e )
logger . error ( f ' 员工操作日志记录失败 ' )
# 用户触发绑定时,及时同步到星云有客中
await event_manager . publish_async ( EventType . BIND_ORDER_FOR_USER , orders [ 0 ] if orders else { } , background_tasks )
return result
@router.post ( " /remark_order " , summary = " 为订单添加额外备注 " )
@unified_resp
async def remark_order ( remark_in : WeixinOrderRemark , login_user : WeixinUserDep ) :
if not remark_in . remark :
logger . warning ( f ' 订单备注为空,将不执行任何操作 ' )
return False
try :
need_monitor_order_list = await weixin_customer_controller . remark_order_by_order_id ( remark = remark_in . remark , order_id = remark_in . order_id )
await action_controller . new_action ( ActionType . WRITE_REMARK , login_user , order_id = remark_in . order_id , remark = remark_in . remark , orders = need_monitor_order_list , done = len ( need_monitor_order_list ) == 0 )
except Exception as e :
logger . exception ( e )
logger . error ( f ' 员工操作日志记录失败 ' )
return bool ( need_monitor_order_list )
@router.post ( " /bind_user " , summary = " 用户绑定客户 " )
@unified_resp
async def bind_user ( bind_info : WeixinUserBindInfo , login_user : WeixinUserDep ) :
result = await weixin_customer_controller . bind_user ( bind_info = bind_info )
try :
await action_controller . new_action ( ActionType . BIND_USER , login_user , * * bind_info . model_dump ( exclude_unset = True ) )
except Exception as e :
logger . exception ( e )
logger . error ( f ' 员工操作日志记录失败 ' )
return result
@router.post ( " /bind_inner_user " , summary = " 用户绑定内部公司成员(erp和企微架构不同) " )
@unified_resp
async def bind_inner_user ( bind_info : WeixinUserBindInfo , login_user : WeixinUserDep ) :
result = await weixin_user_controller . bind_user ( bind_info )
try :
await action_controller . new_action ( ActionType . BIND_USER , login_user , * * bind_info . model_dump ( exclude_unset = True ) )
except Exception as e :
logger . exception ( e )
logger . error ( f ' 员工操作日志记录失败 ' )
return result
@router.get ( " /load_recent_user_from_xingyun " , summary = " 加载最近N天的客户数据 " )
@unified_resp
async def load_user_from_xingyun ( days_range : int = Query ( 3 , description = " 加载最近N天的客户数据 " ) ) :
now_time = datetime . now ( )
start_time = ( now_time - timedelta ( days = days_range ) ) . replace ( hour = 0 , minute = 0 , second = 0 , microsecond = 0 )
end_time = now_time + timedelta ( days = 1 )
return await weixin_customer_controller . load_user_from_xingyun ( add_time_start = start_time , add_time_end = end_time )
@router.get ( " /load_all_user_from_xingyun " , summary = " 加载所有客户数据 " )
@unified_resp
async def load_all_user_from_xingyun ( background_tasks : BackgroundTasks ) :
await event_manager . publish_async ( EventType . SYNC_XINGYUN_CONTACT_INFO , { } , background_tasks )
return True
@router.post ( " /trigger_create_group_chat " , summary = " 触发创建群聊 " )
@unified_resp
async def trigger_create_group_chat ( group_chat : TriggerWeixinGroupChat , login_user : WeixinUserDep ) :
try :
await action_controller . new_action ( ActionType . CREATE_GROUP , login_user , * * group_chat . model_dump ( exclude_unset = True ) )
if group_chat . order_id :
username = login_user . english_name or login_user . nickname
username = username . split ( ' -印刷 ' ) [ 0 ]
remark = f ' 企微联系 { username } 拉群 '
need_monitor_order_list = await weixin_customer_controller . remark_order_by_order_id ( remark = remark , order_id = group_chat . order_id )
await action_controller . new_action ( ActionType . WRITE_REMARK , login_user , order_id = group_chat . order_id , remark = remark , orders = need_monitor_order_list , done = len ( need_monitor_order_list ) == 0 )
except Exception as e :
logger . exception ( e )
logger . error ( f ' 员工操作日志记录失败 ' )
return True