Feature: Add export functionality for worked hours (CSV, JSON, XLSX)
All checks were successful
Build Tamigo CLI / Build Linux Binary (push) Successful in 52s
Build Tamigo CLI / Build Windows Binary (push) Successful in 47s

This commit is contained in:
Daniel Dybing
2026-03-13 22:30:32 +01:00
parent 0271432b23
commit 99445a12e2
4 changed files with 212 additions and 3 deletions

View File

@@ -163,7 +163,7 @@ class TamigoClient:
except: pass
return all_shifts
def calculate_checkins(client):
def select_date_range():
range_choice = questionary.select(
"SELECT TEMPORAL RANGE:" if current_theme_name == "fallout" else "Select period:",
choices=["Last 365 days", "Last 30 days", "This Month", "This Year", "Custom range..."],
@@ -184,7 +184,9 @@ def calculate_checkins(client):
if start_date_dt <= end_date_dt: break
console.print("[error]ERROR: INVALID CHRONOLOGY.[/error]")
except: console.print("[error]ERROR: INVALID DATA FORMAT.[/error]")
return start_date_dt, end_date_dt
def get_worked_days(client, start_date_dt, end_date_dt):
with console.status("[highlight]INITIALIZING DATA RETRIEVAL...[/highlight]" if current_theme_name == "fallout" else "Fetching data..."):
data = client.get_employee_actual_shifts(start_date_dt, end_date_dt)
@@ -201,7 +203,14 @@ def calculate_checkins(client):
if (hours > 0 or item.get("CheckInTime") or item.get("ActualStartTime") or item.get("StartTime")) and not item.get("IsAbsent", False):
if date_str not in work_days: work_days[date_str] = {"hours": hours, "text": item.get("ActualShiftText") or item.get("ActivityName") or "WORKED"}
else: work_days[date_str]["hours"] += hours
return work_days
return None
def calculate_checkins(client):
start_date_dt, end_date_dt = select_date_range()
work_days = get_worked_days(client, start_date_dt, end_date_dt)
if work_days is not None:
if not work_days:
console.print("[warning]WARNING: NO LOG ENTRIES DETECTED.[/warning]")
return
@@ -220,6 +229,67 @@ def calculate_checkins(client):
console.print(Panel(summary_text, title="SUMMARY STATISTICS" if current_theme_name == "fallout" else "Work Statistics", border_style="highlight", expand=False))
else: console.print("[error]FATAL ERROR: DATA RETRIEVAL FAILURE.[/error]")
def export_worked_hours(client):
start_date_dt, end_date_dt = select_date_range()
work_days = get_worked_days(client, start_date_dt, end_date_dt)
if work_days is not None:
if not work_days:
console.print("[warning]WARNING: NO LOG ENTRIES DETECTED.[/warning]")
return
format_choice = questionary.select(
"SELECT EXPORT FORMAT:" if current_theme_name == "fallout" else "Select export format:",
choices=["CSV", "JSON", "XLSX"],
style=theme_data["questionary"]
).ask()
default_filename = f"tamigo_export_{start_date_dt.strftime('%Y%m%d')}_{end_date_dt.strftime('%Y%m%d')}"
filename = questionary.text(
"ENTER FILENAME:" if current_theme_name == "fallout" else "Enter filename:",
default=f"{default_filename}.{format_choice.lower()}",
style=theme_data["questionary"]
).ask()
if not filename: return
try:
if format_choice == "CSV":
import csv
with open(filename, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(["Date", "Hours", "Details"])
for day in sorted(work_days.keys()):
info = work_days[day]
writer.writerow([day, f"{info['hours']:.2f}", info['text']])
elif format_choice == "XLSX":
from openpyxl import Workbook
from openpyxl.styles import Font
wb = Workbook()
ws = wb.active
ws.title = "Worked Hours"
# Header
headers = ["Date", "Hours", "Details"]
ws.append(headers)
for cell in ws[1]:
cell.font = Font(bold=True)
# Data
for day in sorted(work_days.keys()):
info = work_days[day]
ws.append([day, info['hours'], info['text']])
wb.save(filename)
else:
with open(filename, 'w') as f:
json.dump(work_days, f, indent=4)
console.print(f"[success]DATA EXPORTED SUCCESSFULLY TO: {filename}[/success]")
except Exception as e:
console.print(f"[error]ERROR SAVING FILE: {str(e)}[/error]")
else: console.print("[error]FATAL ERROR: DATA RETRIEVAL FAILURE.[/error]")
def main():
print_header()
client = TamigoClient()
@@ -237,11 +307,12 @@ def menu(client):
while True:
choice = questionary.select(
"SELECT ACTION:" if current_theme_name == "fallout" else "What would you like to do?",
choices=["Calculate actual work days", "Show profile info", "Switch UI Theme", "Logout and Exit"],
choices=["Calculate actual work days", "Export hours worked", "Show profile info", "Switch UI Theme", "Logout and Exit"],
style=theme_data["questionary"]
).ask()
if choice == "Calculate actual work days": calculate_checkins(client)
elif choice == "Export hours worked": export_worked_hours(client)
elif choice == "Show profile info":
if client.user_info: console.print_json(data=client.user_info)
else: console.print("[error]ERROR: NO PROFILE INFO.[/error]")