forked from Zhubei_iXD/report_skill_expm
feat: improve project and work package hierarchy handling in week work package logger
This commit is contained in:
parent
0ff400c97c
commit
7f386fce89
|
|
@ -365,6 +365,8 @@ class WeekWorkPackageLogger:
|
|||
project_trees = {}
|
||||
|
||||
# Group entries by project and work package
|
||||
# Note: project_id here is the direct project associated with the time entry,
|
||||
# which may not be the root project but a child project in the hierarchy
|
||||
project_entries = defaultdict(lambda: defaultdict(list))
|
||||
|
||||
for entry in time_entries:
|
||||
|
|
@ -382,7 +384,7 @@ class WeekWorkPackageLogger:
|
|||
|
||||
# Extract linked information
|
||||
user_name = self._get_linked_info(entry, 'user', 'title')
|
||||
project_id = self._get_linked_id(entry, 'project')
|
||||
project_id = self._get_linked_id(entry, 'project') # This is the actual project from time entry
|
||||
activity_name = self._get_linked_info(entry, 'activity', 'title')
|
||||
work_package_id = self._get_linked_id(entry, 'workPackage')
|
||||
|
||||
|
|
@ -397,6 +399,7 @@ class WeekWorkPackageLogger:
|
|||
'hours': hours
|
||||
}
|
||||
|
||||
# Group by the direct project from time entry
|
||||
project_entries[project_id][work_package_id].append(entry_data)
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -405,34 +408,33 @@ class WeekWorkPackageLogger:
|
|||
|
||||
# Build tree structure for each project
|
||||
for project_id, wp_entries in project_entries.items():
|
||||
# Get the full project hierarchy path from root to this project
|
||||
project_path = self._get_project_path(project_id)
|
||||
|
||||
# Build project hierarchy
|
||||
# Build project hierarchy - create all projects in the path
|
||||
current_project_node = None
|
||||
project_root = None
|
||||
|
||||
for proj_id, proj_name in project_path:
|
||||
if proj_id not in project_trees:
|
||||
node = TreeNode(proj_id, proj_name, 'project')
|
||||
project_trees[proj_id] = node
|
||||
if project_root is None:
|
||||
project_root = node
|
||||
project_trees[proj_id] = TreeNode(proj_id, proj_name, 'project')
|
||||
|
||||
if current_project_node is None:
|
||||
# This is the root project in the path
|
||||
current_project_node = project_trees[proj_id]
|
||||
project_root = current_project_node
|
||||
else:
|
||||
# Link parent to child in the project hierarchy
|
||||
if project_trees[proj_id] not in current_project_node.children:
|
||||
current_project_node.add_child(project_trees[proj_id])
|
||||
current_project_node = project_trees[proj_id]
|
||||
|
||||
# If no project path found, create a simple node
|
||||
# If no project path found (no hierarchy support), create a simple node
|
||||
if not project_path and project_id:
|
||||
if project_id not in project_trees:
|
||||
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
|
||||
wp_nodes = {}
|
||||
|
||||
for wp_id, entries in wp_entries.items():
|
||||
|
|
@ -446,6 +448,7 @@ class WeekWorkPackageLogger:
|
|||
|
||||
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_nodes[wp_id_in_path] = TreeNode(wp_id_in_path, wp_name, 'work_package', node_hours, node_entries)
|
||||
|
|
@ -457,7 +460,7 @@ class WeekWorkPackageLogger:
|
|||
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 project
|
||||
# Attach work package hierarchy to the project where time was actually logged
|
||||
if wp_path and current_project_node:
|
||||
root_wp_id = wp_path[0][0]
|
||||
if root_wp_id in wp_nodes:
|
||||
|
|
@ -471,19 +474,24 @@ class WeekWorkPackageLogger:
|
|||
"""Display tree structure in the specified format"""
|
||||
# Find root nodes (nodes without parents in our tree structure)
|
||||
root_nodes = []
|
||||
all_nodes = set(trees.values())
|
||||
all_nodes = set()
|
||||
|
||||
# Collect all nodes from the trees (including nested children)
|
||||
def collect_all_nodes(node):
|
||||
all_nodes.add(node)
|
||||
for child in node.children:
|
||||
collect_all_nodes(child)
|
||||
|
||||
for node in trees.values():
|
||||
collect_all_nodes(node)
|
||||
|
||||
# Find nodes that don't have parents in the tree
|
||||
for node in all_nodes:
|
||||
has_parent_in_tree = False
|
||||
for other_node in all_nodes:
|
||||
if node in other_node.children:
|
||||
has_parent_in_tree = True
|
||||
break
|
||||
|
||||
if not has_parent_in_tree:
|
||||
if node.parent is None or node.parent not in all_nodes:
|
||||
root_nodes.append(node)
|
||||
|
||||
# Sort root nodes by total hours (descending)
|
||||
# Remove duplicates and sort root nodes by total hours (descending)
|
||||
root_nodes = list(set(root_nodes))
|
||||
root_nodes.sort(key=lambda x: x.get_total_hours(), reverse=True)
|
||||
|
||||
print(f"📊 Work Package Time Logging Summary")
|
||||
|
|
@ -524,8 +532,27 @@ class WeekWorkPackageLogger:
|
|||
|
||||
def _generate_json_output(self, trees: Dict[str, TreeNode], start_date: str, end_date: str) -> Dict:
|
||||
"""Generate JSON format output from tree structure"""
|
||||
# Sort root nodes by total hours (descending)
|
||||
root_nodes = sorted(trees.values(), key=lambda x: x.get_total_hours(), reverse=True)
|
||||
# Find root nodes using the same logic as _display_tree
|
||||
root_nodes = []
|
||||
all_nodes = set()
|
||||
|
||||
# Collect all nodes from the trees (including nested children)
|
||||
def collect_all_nodes(node):
|
||||
all_nodes.add(node)
|
||||
for child in node.children:
|
||||
collect_all_nodes(child)
|
||||
|
||||
for node in trees.values():
|
||||
collect_all_nodes(node)
|
||||
|
||||
# Find nodes that don't have parents in the tree
|
||||
for node in all_nodes:
|
||||
if node.parent is None or node.parent not in all_nodes:
|
||||
root_nodes.append(node)
|
||||
|
||||
# Remove duplicates and sort by total hours (descending)
|
||||
root_nodes = list(set(root_nodes))
|
||||
root_nodes.sort(key=lambda x: x.get_total_hours(), reverse=True)
|
||||
|
||||
# Calculate total hours across all projects
|
||||
total_hours = sum(node.get_total_hours() for node in root_nodes)
|
||||
|
|
|
|||
Loading…
Reference in New Issue