fix: 工单创建和飞书同步修复 + 日志精简

1. TSPAssistant.create_work_order 补齐 tenant_id 参数
2. workorder_sync._create_workorder 修复 SQLAlchemy session 泄漏(用 flush 替代 commit+refresh+expunge)
3. _find_existing_workorder 返回 order_id 字符串而非 ORM 对象
4. 飞书同步日志精简:
   - feishu_client API 请求/响应日志降为 DEBUG
   - flexible_field_mapper 字段映射日志降为 DEBUG
   - workorder_sync 字段转换日志降为 DEBUG
   - 只保留关键的创建/同步结果为 INFO
This commit is contained in:
2026-04-07 10:06:29 +08:00
parent 03aa5bd9dc
commit 4ac24d2413
17 changed files with 56 additions and 1260 deletions

View File

@@ -82,11 +82,11 @@ class FeishuClient:
kwargs['headers'] = headers
try:
logger.info(f"发送飞书API请求: {method} {url}")
logger.info(f"请求头: Authorization: Bearer {token[:20]}...")
logger.debug(f"飞书API请求: {method} {url}")
logger.debug(f"请求头: Authorization: Bearer {token[:20]}...")
response = requests.request(method, url, timeout=30, **kwargs)
logger.info(f"飞书API响应状态码: {response.status_code}")
logger.debug(f"飞书API响应状态码: {response.status_code}")
# 处理403权限错误
if response.status_code == 403:
@@ -100,7 +100,7 @@ class FeishuClient:
response.raise_for_status()
result = response.json()
logger.info(f"飞书API响应内容: {result}")
logger.debug(f"飞书API响应内容: {str(result)[:200]}")
return result
except Exception as e:
logger.error(f"飞书API请求失败: {e}")

View File

@@ -418,7 +418,7 @@ class FlexibleFieldMapper:
'mapping_details': {}
}
logger.info(f"开始转换字段: {list(feishu_fields.keys())}")
logger.debug(f"开始转换字段: {list(feishu_fields.keys())}")
for feishu_field, value in feishu_fields.items():
local_field = self.map_field(feishu_field)
@@ -431,7 +431,7 @@ class FlexibleFieldMapper:
'mapped': True,
'value': value
}
logger.info(f"映射字段 {feishu_field} -> {local_field}: {value}")
logger.debug(f"映射字段 {feishu_field} -> {local_field}: {str(value)[:50]}")
else:
conversion_stats['unmapped_fields'].append(feishu_field)
conversion_stats['mapping_details'][feishu_field] = {
@@ -441,7 +441,7 @@ class FlexibleFieldMapper:
}
logger.info(f"飞书字段 {feishu_field} 不存在于数据中")
logger.info(f"字段转换完成: 已映射 {conversion_stats['mapped_fields']}, "
logger.debug(f"字段转换完成: 已映射 {conversion_stats['mapped_fields']}, "
f"未映射 {len(conversion_stats['unmapped_fields'])}")
return local_data, conversion_stats

View File

@@ -310,21 +310,21 @@ class WorkOrderSyncService:
local_data = self._convert_feishu_to_local(fields)
local_data["feishu_record_id"] = record_id
existing_workorder = self._find_existing_workorder(record_id)
existing_order_id = self._find_existing_workorder(record_id)
if existing_workorder:
if existing_order_id:
return {
"success": False,
"message": f"工单已存在: {existing_workorder.order_id}"
"message": f"工单已存在: {existing_order_id}"
}
workorder = self._create_workorder(local_data)
return {
"success": True,
"message": f"工单创建成功: {local_data.get('order_id')}",
"workorder_id": workorder.id,
"order_id": local_data.get('order_id')
"message": f"工单创建成功: {workorder.get('order_id')}",
"workorder_id": workorder.get('id'),
"order_id": workorder.get('order_id')
}
except Exception as e:
@@ -334,45 +334,35 @@ class WorkOrderSyncService:
"message": f"创建工单失败: {str(e)}"
}
def _find_existing_workorder(self, feishu_record_id: str) -> Optional[WorkOrder]:
"""查找已存在的工单"""
def _find_existing_workorder(self, feishu_record_id: str) -> Optional[str]:
"""查找已存在的工单,返回 order_id 或 None"""
try:
with db_manager.get_session() as session:
return session.query(WorkOrder).filter(
wo = session.query(WorkOrder.order_id).filter(
WorkOrder.feishu_record_id == feishu_record_id
).first()
return wo[0] if wo else None
except Exception as e:
logger.error(f"查找现有工单失败: {e}")
return None
def _create_workorder(self, local_data: Dict[str, Any]) -> WorkOrder:
"""创建新工单"""
def _create_workorder(self, local_data: Dict[str, Any]) -> Dict[str, Any]:
"""创建新工单,返回 {id, order_id}"""
try:
with db_manager.get_session() as session:
# 只使用WorkOrder模型支持的字段
valid_data = {}
for key, value in local_data.items():
if hasattr(WorkOrder, key):
# 确保值不是dict、list等复杂类型
if isinstance(value, (dict, list)):
logger.warning(f"字段 '{key}' 包含复杂类型 {type(value).__name__},跳过")
continue
valid_data[key] = value
workorder = WorkOrder(**valid_data)
session.add(workorder)
session.commit()
session.refresh(workorder)
# 在session关闭前访问所有需要的属性让SQLAlchemy加载它们
workorder_id = workorder.id
workorder_order_id = workorder.order_id
# 将对象从session中分离这样它就不再依赖session
session.expunge(workorder)
logger.info(f"创建工单成功: {workorder_order_id}")
return workorder
session.flush() # 获取 ID不 commitcontext manager 会 commit
result = {"id": workorder.id, "order_id": workorder.order_id}
logger.info(f"创建工单成功: {result['order_id']}")
return result
except Exception as e:
logger.error(f"创建工单失败: {e}")
raise
@@ -428,11 +418,11 @@ class WorkOrderSyncService:
def _convert_feishu_to_local(self, feishu_fields: Dict[str, Any]) -> Dict[str, Any]:
"""将飞书字段转换为本地工单字段"""
logger.info(f"开始转换飞书字段: {feishu_fields}")
logger.debug(f"开始转换飞书字段: {list(feishu_fields.keys())}")
local_data, conversion_stats = self.field_mapper.convert_fields(feishu_fields)
logger.info(f"字段转换统计: 总字段 {conversion_stats['total_fields']}, "
logger.debug(f"字段转换统计: 总字段 {conversion_stats['total_fields']}, "
f"已映射 {conversion_stats['mapped_fields']}, "
f"未映射 {len(conversion_stats['unmapped_fields'])}")

View File

@@ -100,14 +100,15 @@ class TSPAssistant:
self.logger.error(f"处理消息异常: {e}")
return {"error": f"处理异常: {str(e)}"}
def create_work_order(self, title: str, description: str, category: str, priority: str = "medium") -> Dict[str, Any]:
def create_work_order(self, title: str, description: str, category: str, priority: str = "medium", tenant_id: str = None) -> Dict[str, Any]:
"""创建工单"""
try:
result = self.dialogue_manager.create_work_order(
title=title,
description=description,
category=category,
priority=priority
priority=priority,
tenant_id=tenant_id
)
if "error" in result: