forked from Zhubei_iXD/report_skill_expm
fix: build complete work package tree with child item retrieval
This commit is contained in:
parent
b57bc6127d
commit
8d1e1e7163
|
|
@ -453,6 +453,69 @@ class WeekWorkPackageLogger:
|
|||
# 3. 若都沒有則填 no-info
|
||||
return NO_INFO
|
||||
|
||||
def _get_work_package_children(self, work_package_id: str) -> List[Dict]:
|
||||
"""獲取 work package 的所有直接子項目"""
|
||||
try:
|
||||
# 使用 OpenProject API 獲取子項目
|
||||
params = {
|
||||
'filters': json.dumps([{
|
||||
'parent': {
|
||||
'operator': '=',
|
||||
'values': [work_package_id]
|
||||
}
|
||||
}])
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
self.work_packages_endpoint,
|
||||
params=params,
|
||||
auth=self._get_auth(),
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return data.get('_embedded', {}).get('elements', [])
|
||||
else:
|
||||
return []
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠ Warning: Could not fetch children for work package {work_package_id}: {e}")
|
||||
return []
|
||||
|
||||
def _build_complete_work_package_tree(self, work_package_id: str, wp_nodes: Dict, time_entries_by_wp: Dict) -> TreeNode:
|
||||
"""遞歸建構完整的 work package 樹狀結構(包含所有子項目)"""
|
||||
if work_package_id in wp_nodes:
|
||||
return wp_nodes[work_package_id]
|
||||
|
||||
# 獲取 work package 詳細資料
|
||||
wp_data = self._get_work_package_details(work_package_id)
|
||||
if not wp_data:
|
||||
return None
|
||||
|
||||
wp_name = wp_data.get('subject', f'WP-{work_package_id}')
|
||||
|
||||
# 檢查是否有時間記錄
|
||||
entries = time_entries_by_wp.get(work_package_id, [])
|
||||
node_hours = sum(entry['hours'] for entry in entries)
|
||||
|
||||
# 獲取完成度
|
||||
wp_completion = self._get_work_package_completion(work_package_id)
|
||||
|
||||
# 創建節點
|
||||
node = TreeNode(work_package_id, wp_name, 'work_package', node_hours, entries, wp_completion)
|
||||
wp_nodes[work_package_id] = node
|
||||
|
||||
# 獲取所有子項目
|
||||
children_data = self._get_work_package_children(work_package_id)
|
||||
for child_data in children_data:
|
||||
child_id = str(child_data.get('id'))
|
||||
child_node = self._build_complete_work_package_tree(child_id, wp_nodes, time_entries_by_wp)
|
||||
if child_node:
|
||||
node.add_child(child_node)
|
||||
|
||||
return node
|
||||
|
||||
def _get_project_completion(self, project_id: str) -> str:
|
||||
"""Project不計算完成度"""
|
||||
return None
|
||||
|
|
@ -597,40 +660,22 @@ class WeekWorkPackageLogger:
|
|||
project_trees[project_id] = TreeNode(project_id, f"Project-{project_id}", 'project')
|
||||
current_project_node = project_trees[project_id]
|
||||
|
||||
# Build work package hierarchy for this project
|
||||
# current_project_node now points to the actual project where time was logged
|
||||
# 建構完整的 work package 層級結構
|
||||
wp_nodes = {}
|
||||
root_wp_nodes = set()
|
||||
|
||||
for wp_id, entries in wp_entries.items():
|
||||
# 首先找出所有根 work package(通過檢查父子關係)
|
||||
for wp_id in wp_entries.keys():
|
||||
wp_path = self._get_work_package_path(wp_id)
|
||||
|
||||
# Calculate total hours for this work package
|
||||
total_hours = sum(entry['hours'] for entry in entries)
|
||||
|
||||
# Build work package hierarchy
|
||||
current_wp_node = None
|
||||
|
||||
for wp_id_in_path, wp_name in wp_path:
|
||||
if wp_id_in_path not in wp_nodes:
|
||||
# Only attach entries to the actual work package (not parent work packages)
|
||||
node_entries = entries if wp_id_in_path == wp_id else []
|
||||
node_hours = total_hours if wp_id_in_path == wp_id else 0
|
||||
wp_completion = self._get_work_package_completion(wp_id_in_path)
|
||||
wp_nodes[wp_id_in_path] = TreeNode(wp_id_in_path, wp_name, 'work_package', node_hours, node_entries, wp_completion)
|
||||
|
||||
if current_wp_node is None:
|
||||
current_wp_node = wp_nodes[wp_id_in_path]
|
||||
else:
|
||||
if wp_nodes[wp_id_in_path] not in current_wp_node.children:
|
||||
current_wp_node.add_child(wp_nodes[wp_id_in_path])
|
||||
current_wp_node = wp_nodes[wp_id_in_path]
|
||||
|
||||
# Attach work package hierarchy to the project where time was actually logged
|
||||
if wp_path and current_project_node:
|
||||
if wp_path:
|
||||
root_wp_id = wp_path[0][0]
|
||||
if root_wp_id in wp_nodes:
|
||||
root_wp_node = wp_nodes[root_wp_id]
|
||||
if root_wp_node not in current_project_node.children:
|
||||
root_wp_nodes.add(root_wp_id)
|
||||
|
||||
# 為每個根 work package 建構完整樹狀結構
|
||||
for root_wp_id in root_wp_nodes:
|
||||
if current_project_node:
|
||||
root_wp_node = self._build_complete_work_package_tree(root_wp_id, wp_nodes, wp_entries)
|
||||
if root_wp_node and root_wp_node not in current_project_node.children:
|
||||
current_project_node.add_child(root_wp_node)
|
||||
|
||||
return project_trees
|
||||
|
|
|
|||
Loading…
Reference in New Issue