Move data export and data formatting functions into own modules.

This commit is contained in:
2025-07-01 11:00:25 +02:00
committed by Jens Luedicke
parent 141c7d4ee4
commit 63de80f752
3 changed files with 595 additions and 571 deletions

147
data_formatting.py Normal file
View File

@@ -0,0 +1,147 @@
"""
Data formatting utilities for TimeTrack application.
Handles conversion of time entries and analytics data to various display formats.
"""
from datetime import datetime
from collections import defaultdict
def format_duration(seconds):
"""Format duration in seconds to HH:MM:SS format."""
if seconds is None:
return '00:00:00'
hours = seconds // 3600
minutes = (seconds % 3600) // 60
seconds = seconds % 60
return f"{hours:d}:{minutes:02d}:{seconds:02d}"
def prepare_export_data(entries):
"""Prepare time entries data for export."""
data = []
for entry in entries:
row = {
'Date': entry.arrival_time.strftime('%Y-%m-%d'),
'Project Code': entry.project.code if entry.project else '',
'Project Name': entry.project.name if entry.project else '',
'Arrival Time': entry.arrival_time.strftime('%H:%M:%S'),
'Departure Time': entry.departure_time.strftime('%H:%M:%S') if entry.departure_time else 'Active',
'Work Duration (HH:MM:SS)': format_duration(entry.duration) if entry.duration is not None else 'In progress',
'Break Duration (HH:MM:SS)': format_duration(entry.total_break_duration),
'Work Duration (seconds)': entry.duration if entry.duration is not None else 0,
'Break Duration (seconds)': entry.total_break_duration if entry.total_break_duration is not None else 0,
'Notes': entry.notes if entry.notes else ''
}
data.append(row)
return data
def prepare_team_hours_export_data(team, team_data, date_range):
"""Prepare team hours data for export."""
export_data = []
for member_data in team_data:
user = member_data['user']
daily_hours = member_data['daily_hours']
# Create base row with member info
row = {
'Team': team['name'],
'Member': user['username'],
'Email': user['email'],
'Total Hours': member_data['total_hours']
}
# Add daily hours columns
for date_str in date_range:
formatted_date = datetime.strptime(date_str, '%Y-%m-%d').strftime('%m/%d/%Y')
row[formatted_date] = daily_hours.get(date_str, 0.0)
export_data.append(row)
return export_data
def format_table_data(entries):
"""Format data for table view in analytics."""
formatted_entries = []
for entry in entries:
formatted_entry = {
'id': entry.id,
'date': entry.arrival_time.strftime('%Y-%m-%d'),
'arrival_time': entry.arrival_time.strftime('%H:%M:%S'),
'departure_time': entry.departure_time.strftime('%H:%M:%S') if entry.departure_time else 'Active',
'duration': format_duration(entry.duration) if entry.duration else 'In progress',
'break_duration': format_duration(entry.total_break_duration),
'project_code': entry.project.code if entry.project else None,
'project_name': entry.project.name if entry.project else 'No Project',
'notes': entry.notes or '',
'user_name': entry.user.username
}
formatted_entries.append(formatted_entry)
return {'entries': formatted_entries}
def format_graph_data(entries, granularity='daily'):
"""Format data for graph visualization in analytics."""
# Group data by date
daily_data = defaultdict(lambda: {'total_hours': 0, 'projects': defaultdict(int)})
project_totals = defaultdict(int)
for entry in entries:
if entry.departure_time and entry.duration:
date_key = entry.arrival_time.strftime('%Y-%m-%d')
hours = entry.duration / 3600 # Convert seconds to hours
daily_data[date_key]['total_hours'] += hours
project_name = entry.project.name if entry.project else 'No Project'
daily_data[date_key]['projects'][project_name] += hours
project_totals[project_name] += hours
# Format time series data
time_series = []
for date, data in sorted(daily_data.items()):
time_series.append({
'date': date,
'hours': round(data['total_hours'], 2)
})
# Format project distribution
project_distribution = [
{'project': project, 'hours': round(hours, 2)}
for project, hours in project_totals.items()
]
return {
'timeSeries': time_series,
'projectDistribution': project_distribution,
'totalHours': sum(project_totals.values()),
'totalDays': len(daily_data)
}
def format_team_data(entries, granularity='daily'):
"""Format data for team view in analytics."""
# Group by user and date
user_data = defaultdict(lambda: {'daily_hours': defaultdict(float), 'total_hours': 0})
for entry in entries:
if entry.departure_time and entry.duration:
date_key = entry.arrival_time.strftime('%Y-%m-%d')
hours = entry.duration / 3600
user_data[entry.user.username]['daily_hours'][date_key] += hours
user_data[entry.user.username]['total_hours'] += hours
# Format for frontend
team_data = []
for username, data in user_data.items():
team_data.append({
'username': username,
'daily_hours': dict(data['daily_hours']),
'total_hours': round(data['total_hours'], 2)
})
return {'team_data': team_data}