'新增计划字段+持续同步功能'
This commit is contained in:
parent
ecf9ccbc0b
commit
7db5d87a94
@ -10,7 +10,7 @@ docid = dcOsT3czWy0YEDg38vlDqwVCTjv0kzwC_GU2XmT9wSZctQ0ZJQUAV7vMQ3ljZx-n_NqxzEEY
|
||||
|
||||
[Schedule]
|
||||
# 同步频率(分钟)
|
||||
sync_interval = 1
|
||||
sync_interval = 30
|
||||
|
||||
[wework]
|
||||
# 企业微信应用ID
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{
|
||||
"access_token": "LsTV1Z6Ye4h2c77s1oKx4zasisAn4QiTbqXmZRUYchZRzp6Q_igpVWp22oEhv8rTHuYyB1LKfqhLjQ9qvgwU13fZns6t-aNBDMw00BBf76V2XqoKKXPHNQZGKQly8RH9NgFMoqfYiKeDnoCdbYnvRjgn8oYoc0AvnCu_qU9TdP8XJgLO01-inoLGSEdTLZnWXf90uf4RztU8xH1a7nuM1p31w58AT7iV3h8Uv9aPOe8",
|
||||
"fetch_time": 1767954012.568217
|
||||
"access_token": "9-OFdr2nbGo-1sSAYBujyvTtP5v88W0MjLSy3BzHayMEw0tX0tQ8qsbYXshNdHURsLqjXh4dVaRs2HIxvy2gXbWglBg90YtJU_3Yxfz-EXkCUT6Yyt1U1Z6ojUzWkwG6esUX9rWndHWK7hdXusZj5vpHBqVyQpY1Pi3eVKpB28puC_7IXsgbUaW5-JenDP3C7AnAs_x7jbsECXD8Y2XjZymhBKEwf_jZH-iK1Ojnvxk",
|
||||
"fetch_time": 1768214302.441097
|
||||
}
|
||||
@ -227,27 +227,25 @@ class SmartSheetSync:
|
||||
# 直接使用任务一的 update_records 方法(已添加debug=1)
|
||||
return self.api.update_records(sheet_id, update_records)
|
||||
|
||||
def get_records_with_tapd_link(self, sheet_id: str) -> List[Dict]:
|
||||
def get_records_with_tapd_link(self, sheet_id: str,
|
||||
all_records: List[Dict] = None) -> List[Dict]:
|
||||
"""
|
||||
获取所有包含TAPD链接的记录
|
||||
获取所有包含TAPD链接的新记录(同步状态为空)
|
||||
|
||||
Args:
|
||||
sheet_id: 子表ID
|
||||
all_records: 可选,已获取的所有记录列表,避免重复获取
|
||||
|
||||
Returns:
|
||||
List[Dict]: 包含TAPD链接的记录列表,每条记录包含:
|
||||
- record: 原始记录对象
|
||||
- record_id: 记录ID
|
||||
- tapd_link: TAPD链接
|
||||
- story_id: 解析出的需求单号(如果解析成功)
|
||||
- parse_success: 链接解析是否成功
|
||||
- parse_error: 解析失败的错误信息
|
||||
List[Dict]: 包含TAPD链接的记录列表
|
||||
"""
|
||||
print(f"正在获取包含TAPD链接的记录...")
|
||||
print(f"正在获取包含TAPD链接的新记录...")
|
||||
|
||||
if all_records is None:
|
||||
all_records = self.get_all_records(sheet_id)
|
||||
|
||||
all_records = self.get_all_records(sheet_id)
|
||||
records_with_link = []
|
||||
skipped_synced_count = 0 # 统计跳过的已同步记录数
|
||||
skipped_synced_count = 0
|
||||
|
||||
for record in all_records:
|
||||
tapd_link = self.extract_tapd_link(record)
|
||||
@ -313,6 +311,68 @@ class SmartSheetSync:
|
||||
FIELD_PLAN: self.api.get_field_value_by_title(record, FIELD_PLAN),
|
||||
}
|
||||
|
||||
def get_synced_records_for_update(self, sheet_id: str,
|
||||
terminal_statuses: List[str],
|
||||
all_records: List[Dict] = None) -> List[Dict]:
|
||||
"""
|
||||
获取需要持续同步的已同步记录
|
||||
|
||||
筛选条件:
|
||||
- 同步状态 = "成功"
|
||||
- TAPD状态 不在终态列表中
|
||||
|
||||
Args:
|
||||
sheet_id: 子表ID
|
||||
terminal_statuses: 终态列表(如 ['已完成', '取消'])
|
||||
all_records: 可选,已获取的所有记录列表,避免重复获取
|
||||
|
||||
Returns:
|
||||
List[Dict]: 需要持续同步的记录列表
|
||||
"""
|
||||
print(f"正在获取需要持续同步的记录...")
|
||||
|
||||
if all_records is None:
|
||||
all_records = self.get_all_records(sheet_id)
|
||||
records_for_update = []
|
||||
skipped_terminal_count = 0
|
||||
|
||||
for record in all_records:
|
||||
# 检查同步状态是否为"成功"
|
||||
sync_status = self.api.get_field_value_by_title(record, FIELD_SYNC_STATUS)
|
||||
if sync_status != "成功":
|
||||
continue
|
||||
|
||||
# 检查TAPD链接是否存在
|
||||
tapd_link = self.extract_tapd_link(record)
|
||||
if not tapd_link:
|
||||
continue
|
||||
|
||||
# 检查TAPD状态是否为终态
|
||||
tapd_status = self.api.get_field_value_by_title(record, FIELD_TAPD_STATUS)
|
||||
if tapd_status in terminal_statuses:
|
||||
skipped_terminal_count += 1
|
||||
continue
|
||||
|
||||
# 解析链接获取story_id
|
||||
success, result, link_type = parse_tapd_link(tapd_link)
|
||||
if not success:
|
||||
continue
|
||||
|
||||
record_info = {
|
||||
"record": record,
|
||||
"record_id": record.get('record_id', ''),
|
||||
"tapd_link": tapd_link,
|
||||
"story_id": result,
|
||||
"current_status": tapd_status,
|
||||
}
|
||||
records_for_update.append(record_info)
|
||||
|
||||
print(f" ✓ 找到 {len(records_for_update)} 条需要持续同步的记录")
|
||||
if skipped_terminal_count > 0:
|
||||
print(f" - 跳过终态记录: {skipped_terminal_count} 条")
|
||||
|
||||
return records_for_update
|
||||
|
||||
|
||||
def process_sheet(api: SmartSheetSync, sheet_id: str, sheet_title: str) -> Dict:
|
||||
"""
|
||||
|
||||
@ -20,7 +20,7 @@ sys.path.insert(0, str(project_root))
|
||||
from src.token_manager import TokenManager
|
||||
from src2.config import Task2ConfigManager
|
||||
from src2.logger import get_task2_logger
|
||||
from src2.tapd_api import TAPDStoryApi
|
||||
from src2.tapd_api import TAPDStoryApi, TERMINAL_STATUSES
|
||||
from src2.smartsheet_sync import SmartSheetSync, REQUIRED_FIELDS
|
||||
|
||||
|
||||
@ -181,65 +181,76 @@ class SyncService:
|
||||
print(f" ⚠ 跳过此子表: {sheet_result['skip_reason']}")
|
||||
return sheet_result
|
||||
|
||||
# 2. 获取包含TAPD链接的记录
|
||||
records_with_link = self.smartsheet.get_records_with_tapd_link(sheet_id)
|
||||
# 2. 获取所有记录(只获取一次,供新记录同步和持续同步共用)
|
||||
print(f"正在获取所有记录...")
|
||||
all_records = self.smartsheet.get_all_records(sheet_id)
|
||||
|
||||
# 3. 获取包含TAPD链接的新记录(同步状态为空)
|
||||
records_with_link = self.smartsheet.get_records_with_tapd_link(
|
||||
sheet_id, all_records=all_records
|
||||
)
|
||||
sheet_result["records_with_link"] = len(records_with_link)
|
||||
|
||||
if not records_with_link:
|
||||
print(f" ℹ 没有包含TAPD链接的记录")
|
||||
return sheet_result
|
||||
# 4. 处理新记录
|
||||
if records_with_link:
|
||||
print(f"\n--- 新记录同步 ---")
|
||||
success_records = [] # 成功同步的记录
|
||||
failed_record_ids = [] # 失败的记录ID列表
|
||||
|
||||
# 3. 处理每条记录
|
||||
success_records = [] # 成功同步的记录(包含业务字段 + 同步状态)
|
||||
failed_record_ids = [] # 失败的记录ID列表
|
||||
for record_info in records_with_link:
|
||||
record_result = self._process_record(record_info)
|
||||
sheet_result["details"].append(record_result)
|
||||
|
||||
for record_info in records_with_link:
|
||||
record_result = self._process_record(record_info)
|
||||
sheet_result["details"].append(record_result)
|
||||
if record_result["success"]:
|
||||
sheet_result["records_synced"] += 1
|
||||
|
||||
if record_result["success"]:
|
||||
sheet_result["records_synced"] += 1
|
||||
if record_result["update_record"]:
|
||||
success_records.append(record_result["update_record"])
|
||||
sheet_result["records_updated"] += 1
|
||||
else:
|
||||
sheet_result["records_failed"] += 1
|
||||
failed_record_ids.append(record_info["record_id"])
|
||||
|
||||
if record_result["update_record"]:
|
||||
success_records.append(record_result["update_record"])
|
||||
sheet_result["records_updated"] += 1
|
||||
else:
|
||||
sheet_result["records_failed"] += 1
|
||||
failed_record_ids.append(record_info["record_id"])
|
||||
# 收集失败记录的详细信息用于推送
|
||||
failed_record = {
|
||||
"sheet_title": sheet_title,
|
||||
"record_id": record_info["record_id"],
|
||||
"tapd_link": record_info.get("tapd_link", "(无链接)"),
|
||||
"error_message": record_result.get("error_message", "未知错误")
|
||||
}
|
||||
sheet_result["failed_records"].append(failed_record)
|
||||
|
||||
# 收集失败记录的详细信息用于推送
|
||||
failed_record = {
|
||||
"sheet_title": sheet_title,
|
||||
"record_id": record_info["record_id"],
|
||||
"tapd_link": record_info.get("tapd_link", "(无链接)"),
|
||||
"error_message": record_result.get("error_message", "未知错误")
|
||||
}
|
||||
sheet_result["failed_records"].append(failed_record)
|
||||
# 4. 批量回写成功记录
|
||||
if success_records:
|
||||
print(f"\n正在回写 {len(success_records)} 条成功记录...")
|
||||
try:
|
||||
self.smartsheet.batch_update_records(sheet_id, success_records)
|
||||
print(f" ✓ 成功记录回写完成")
|
||||
except Exception as e:
|
||||
print(f" ✗ 成功记录回写失败: {e}")
|
||||
|
||||
# 4. 批量回写成功记录(业务字段 + 同步状态=成功)
|
||||
if success_records:
|
||||
print(f"\n正在回写 {len(success_records)} 条成功记录...")
|
||||
try:
|
||||
self.smartsheet.batch_update_records(sheet_id, success_records)
|
||||
print(f" ✓ 成功记录回写完成")
|
||||
except Exception as e:
|
||||
print(f" ✗ 成功记录回写失败: {e}")
|
||||
# 5. 批量回写失败记录
|
||||
if failed_record_ids:
|
||||
print(f"\n正在回写 {len(failed_record_ids)} 条失败记录的状态...")
|
||||
try:
|
||||
failed_updates = [
|
||||
self.smartsheet.build_update_record(
|
||||
record_id=record_id,
|
||||
sync_status="失败"
|
||||
)
|
||||
for record_id in failed_record_ids
|
||||
]
|
||||
self.smartsheet.batch_update_records(sheet_id, failed_updates)
|
||||
print(f" ✓ 失败记录状态回写完成")
|
||||
except Exception as e:
|
||||
print(f" ✗ 失败记录状态回写失败: {e}")
|
||||
else:
|
||||
print(f" ℹ 没有新记录需要同步")
|
||||
|
||||
# 5. 批量回写失败记录(只写入同步状态=失败)
|
||||
if failed_record_ids:
|
||||
print(f"\n正在回写 {len(failed_record_ids)} 条失败记录的状态...")
|
||||
try:
|
||||
failed_updates = [
|
||||
self.smartsheet.build_update_record(
|
||||
record_id=record_id,
|
||||
sync_status="失败"
|
||||
)
|
||||
for record_id in failed_record_ids
|
||||
]
|
||||
self.smartsheet.batch_update_records(sheet_id, failed_updates)
|
||||
print(f" ✓ 失败记录状态回写完成")
|
||||
except Exception as e:
|
||||
print(f" ✗ 失败记录状态回写失败: {e}")
|
||||
# 7. 持续同步:更新已同步记录的最新状态
|
||||
print(f"\n--- 持续同步 ---")
|
||||
update_result = self._process_synced_records_update(sheet_id, all_records=all_records)
|
||||
sheet_result["continuous_sync"] = update_result
|
||||
|
||||
sheet_result["total_records"] = len(records_with_link)
|
||||
|
||||
@ -371,6 +382,82 @@ class SyncService:
|
||||
|
||||
return False
|
||||
|
||||
def _process_synced_records_update(self, sheet_id: str,
|
||||
all_records: List[Dict] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
处理已同步记录的状态更新(持续同步)
|
||||
|
||||
Args:
|
||||
sheet_id: 子表ID
|
||||
all_records: 可选,已获取的所有记录列表
|
||||
|
||||
Returns:
|
||||
Dict: 更新结果统计
|
||||
"""
|
||||
result = {
|
||||
"checked": 0,
|
||||
"updated": 0,
|
||||
"failed": 0,
|
||||
}
|
||||
|
||||
# 获取需要持续同步的记录
|
||||
records = self.smartsheet.get_synced_records_for_update(
|
||||
sheet_id, TERMINAL_STATUSES, all_records=all_records
|
||||
)
|
||||
|
||||
if not records:
|
||||
print(f" ℹ 没有需要持续同步的记录")
|
||||
return result
|
||||
|
||||
result["checked"] = len(records)
|
||||
updates = []
|
||||
|
||||
for record_info in records:
|
||||
try:
|
||||
# 查询TAPD最新状态
|
||||
story_info = self.tapd_api.get_story(record_info["story_id"])
|
||||
|
||||
# 提取最新字段值
|
||||
new_status = story_info.get('status', '')
|
||||
new_owner = story_info.get('owner', '')
|
||||
new_begin = story_info.get('begin', '')
|
||||
new_due = story_info.get('due', '')
|
||||
plan_id = story_info.get('custom_plan_field_1', '')
|
||||
new_plan = self.tapd_api.map_plan_id_to_name(plan_id)
|
||||
|
||||
# 获取当前值并比较
|
||||
current = self.smartsheet.get_current_field_values(record_info["record"])
|
||||
needs_update = self._check_needs_update(
|
||||
current, new_status, new_owner, new_begin, new_due, new_plan
|
||||
)
|
||||
|
||||
if needs_update:
|
||||
update_record = self.smartsheet.build_update_record(
|
||||
record_id=record_info["record_id"],
|
||||
status=new_status,
|
||||
owner=new_owner,
|
||||
begin_date=new_begin,
|
||||
due_date=new_due,
|
||||
plan=new_plan
|
||||
)
|
||||
updates.append(update_record)
|
||||
|
||||
except Exception as e:
|
||||
result["failed"] += 1
|
||||
if self.test_mode:
|
||||
print(f" ✗ 记录 {record_info['record_id']} 更新失败: {e}")
|
||||
|
||||
# 批量更新
|
||||
if updates:
|
||||
print(f" 正在更新 {len(updates)} 条记录...")
|
||||
self.smartsheet.batch_update_records(sheet_id, updates)
|
||||
result["updated"] = len(updates)
|
||||
print(f" ✓ 持续同步更新完成")
|
||||
else:
|
||||
print(f" ✓ 所有记录状态均未变化")
|
||||
|
||||
return result
|
||||
|
||||
def _send_failure_notification(self, failed_records: List[Dict]) -> None:
|
||||
"""
|
||||
发送同步失败通知
|
||||
|
||||
@ -28,6 +28,9 @@ STATUS_MAPPING = {
|
||||
"status_13": "待评审",
|
||||
}
|
||||
|
||||
# 需求终态列表(这些状态不需要持续同步)
|
||||
TERMINAL_STATUSES = ['已完成', '取消']
|
||||
|
||||
|
||||
def map_status(status_code: str) -> str:
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user