Created
April 5, 2025 15:05
-
-
Save jranil/d52977683e1e771ce5cd83ea453165e1 to your computer and use it in GitHub Desktop.
A Python script that generates a comprehensive Excel/Google Sheets Kanban-style task tracking (To Do, In Progress, Blocked, Done) compatible task tracking system with automated dashboards.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pandas as pd | |
import os | |
from datetime import datetime, timedelta | |
import openpyxl | |
from openpyxl.styles import PatternFill, Font, Alignment, Border, Side | |
from openpyxl.utils import get_column_letter | |
from openpyxl.chart import BarChart, Reference, LineChart | |
from openpyxl.worksheet.datavalidation import DataValidation | |
def create_task_prefix(name): | |
if not name or len(name) < 2: | |
return "TK" | |
name_parts = name.split() | |
if len(name_parts) == 1: | |
return f"{name[0]}{name[-1]}".upper() | |
else: | |
return f"{name_parts[0][0]}{name_parts[-1][0]}".upper() | |
def create_team_tracking_sheet(): | |
print("===== Team Activity Tracking System =====") | |
team_name = input("Enter team name: ") | |
if not team_name: | |
team_name = "My Team" | |
print("\nEnter team members (one per line, enter 'done' when finished):") | |
team_members = [] | |
while True: | |
name = input("> ") | |
if name.lower() == 'done': | |
break | |
team_members.append(name) | |
if not team_members: | |
print("No team members added. Exiting.") | |
return | |
week_start_options = { | |
"1": "Monday", | |
"2": "Tuesday", | |
"3": "Wednesday", | |
"4": "Thursday", | |
"5": "Friday", | |
"6": "Saturday", | |
"7": "Sunday" | |
} | |
print("\nSelect week start day:") | |
for key, day in week_start_options.items(): | |
print(f"{key}. {day}") | |
week_start_choice = input("> ") | |
if week_start_choice not in week_start_options: | |
print("Invalid choice. Defaulting to Monday.") | |
week_start_day = 0 # Monday | |
else: | |
week_start_day = int(week_start_choice) - 1 | |
wb = openpyxl.Workbook() | |
default_sheet = wb.active | |
wb.remove(default_sheet) | |
member_prefixes = {} | |
for member in team_members: | |
prefix = create_task_prefix(member) | |
counter = 1 | |
while prefix in member_prefixes.values(): | |
prefix = f"{prefix[0]}{counter}{prefix[-1]}" | |
counter += 1 | |
member_prefixes[member] = prefix | |
dashboard = wb.create_sheet("Dashboard") | |
setup_dashboard(dashboard, team_members, member_prefixes, team_name) | |
for member in team_members: | |
member_sheet = wb.create_sheet(member) | |
setup_member_sheet(member_sheet, member, member_prefixes[member]) | |
weekly_dashboard = wb.create_sheet("Weekly Activity") | |
setup_weekly_dashboard(weekly_dashboard, team_members, team_name, week_start_day) | |
monthly_dashboard = wb.create_sheet("Monthly Activity") | |
setup_monthly_dashboard(monthly_dashboard, team_members, team_name) | |
filename = f"{team_name.replace(' ', '_')}_tracker_{datetime.now().strftime('%Y%m%d_%H%M')}.xlsx" | |
wb.save(filename) | |
print(f"\nFile created successfully: {filename}") | |
print(f"You can import this file into Google Sheets.") | |
def setup_dashboard(sheet, team_members, member_prefixes, team_name): | |
sheet.sheet_properties.tabColor = "1072BA" | |
title_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") | |
header_fill = PatternFill(start_color="D9E1F2", end_color="D9E1F2", fill_type="solid") | |
critical_fill = PatternFill(start_color="FFD9D9", end_color="FFD9D9", fill_type="solid") | |
thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), | |
top=Side(style='thin'), bottom=Side(style='thin')) | |
sheet['A1'] = f"{team_name.upper()} - ACTIVITY DASHBOARD" | |
sheet['A1'].font = Font(bold=True, size=16, color="FFFFFF") | |
sheet['A1'].fill = title_fill | |
sheet.merge_cells('A1:G1') | |
sheet['A1'].alignment = Alignment(horizontal='center') | |
current_date = datetime.now().strftime("%Y-%m-%d") | |
sheet['A2'] = f"Last updated: {current_date}" | |
sheet.merge_cells('A2:G2') | |
sheet['A2'].alignment = Alignment(horizontal='center') | |
headers = ["Team Member", "To Do", "In Progress", "Blocked", "Done", "Critical", "Total"] | |
for col, header in enumerate(headers, 1): | |
cell = sheet.cell(row=3, column=col, value=header) | |
cell.font = Font(bold=True) | |
cell.fill = header_fill | |
cell.border = thin_border | |
cell.alignment = Alignment(horizontal='center') | |
sheet.column_dimensions[get_column_letter(col)].width = 15 | |
for row, member in enumerate(team_members, 4): | |
sheet.cell(row=row, column=1, value=member).alignment = Alignment(horizontal='left') | |
sheet.cell(row=row, column=2, value=f"=COUNTIF('{member}'!C:C, \"To Do\")") | |
sheet.cell(row=row, column=3, value=f"=COUNTIF('{member}'!C:C, \"In Progress\")") | |
sheet.cell(row=row, column=4, value=f"=COUNTIF('{member}'!C:C, \"Blocked\")") | |
sheet.cell(row=row, column=5, value=f"=COUNTIF('{member}'!C:C, \"Done\")") | |
sheet.cell(row=row, column=6, value=f"=COUNTIF('{member}'!D:D, \"Critical\")") | |
sheet.cell(row=row, column=7, value=f"=SUM(B{row}:E{row})") | |
for col in range(1, 8): | |
sheet.cell(row=row, column=col).border = thin_border | |
sheet.cell(row=row, column=col).alignment = Alignment(horizontal='center') | |
if col == 6: | |
sheet.cell(row=row, column=col).fill = critical_fill | |
total_row = len(team_members) + 4 | |
sheet.cell(row=total_row, column=1, value="TOTALS") | |
sheet.cell(row=total_row, column=1).font = Font(bold=True) | |
sheet.cell(row=total_row, column=1).alignment = Alignment(horizontal='left') | |
for col in range(2, 8): | |
col_letter = get_column_letter(col) | |
cell = sheet.cell(row=total_row, column=col, value=f"=SUM({col_letter}4:{col_letter}{total_row - 1})") | |
cell.font = Font(bold=True) | |
cell.border = thin_border | |
cell.alignment = Alignment(horizontal='center') | |
chart = BarChart() | |
chart.title = "Task Distribution by Team Member" | |
chart.x_axis.title = "Team Members" | |
chart.y_axis.title = "Number of Tasks" | |
data = Reference(sheet, min_col=2, min_row=3, max_col=5, max_row=total_row - 1) | |
cats = Reference(sheet, min_col=1, min_row=4, max_row=total_row - 1) | |
chart.add_data(data, titles_from_data=True) | |
chart.set_categories(cats) | |
sheet.add_chart(chart, "A" + str(total_row + 2)) | |
def setup_member_sheet(sheet, member_name, member_prefix): | |
sheet.sheet_properties.tabColor = "92D050" | |
thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), | |
top=Side(style='thin'), bottom=Side(style='thin')) | |
title_fill = PatternFill(start_color="70AD47", end_color="70AD47", fill_type="solid") | |
header_fill = PatternFill(start_color="E2EFDA", end_color="E2EFDA", fill_type="solid") | |
todo_fill = PatternFill(start_color="FFEB9C", end_color="FFEB9C", fill_type="solid") | |
progress_fill = PatternFill(start_color="D9E1F2", end_color="D9E1F2", fill_type="solid") | |
blocked_fill = PatternFill(start_color="FFD9D9", end_color="FFD9D9", fill_type="solid") | |
done_fill = PatternFill(start_color="E2EFDA", end_color="E2EFDA", fill_type="solid") | |
mandatory_fill = PatternFill(start_color="FCE4D6", end_color="FCE4D6", fill_type="solid") | |
sheet['A1'] = f"{member_name}'s Task Board" | |
sheet['A1'].font = Font(bold=True, size=14, color="FFFFFF") | |
sheet['A1'].fill = title_fill | |
sheet.merge_cells('A1:G1') | |
sheet['A1'].alignment = Alignment(horizontal='center') | |
sheet['G2'] = "* Required fields" | |
sheet['G2'].font = Font(italic=True) | |
sheet['G2'].alignment = Alignment(horizontal='right') | |
headers = ["Task ID", "Task Description*", "Status*", "Priority", "Due Date*", "Created Date", "Notes"] | |
for col, header in enumerate(headers, 1): | |
cell = sheet.cell(row=3, column=col, value=header) | |
cell.font = Font(bold=True) | |
cell.fill = header_fill | |
cell.border = thin_border | |
cell.alignment = Alignment(horizontal='center') | |
if col == 2 or col == 3 or col == 5: | |
cell.fill = mandatory_fill | |
if col == 2: | |
sheet.column_dimensions[get_column_letter(col)].width = 40 | |
elif col == 7: | |
sheet.column_dimensions[get_column_letter(col)].width = 25 | |
else: | |
sheet.column_dimensions[get_column_letter(col)].width = 15 | |
status_validation = DataValidation( | |
type="list", | |
formula1='"To Do,In Progress,Blocked,Done"', | |
allow_blank=False | |
) | |
priority_validation = DataValidation( | |
type="list", | |
formula1='"Critical,High,Normal,Low"', | |
allow_blank=True | |
) | |
sheet.add_data_validation(status_validation) | |
sheet.add_data_validation(priority_validation) | |
for row in range(4, 54): | |
sheet.cell(row=row, column=1, value=f"=IF(B{row}<>\"\",\"{member_prefix}-\"&ROW()-3,\"\")") | |
created_date_cell = sheet.cell(row=row, column=6, value=f"=IF(B{row}<>\"\",TODAY(),\"\")") | |
created_date_cell.number_format = "yyyy-mm-dd" | |
due_date_cell = sheet.cell(row=row, column=5) | |
due_date_cell.number_format = "yyyy-mm-dd" | |
for col in range(1, 8): | |
sheet.cell(row=row, column=col).border = Side(style='thin') | |
if col == 2 or col == 7: | |
sheet.cell(row=row, column=col).alignment = Alignment(horizontal='left', vertical='top', wrap_text=True) | |
else: | |
sheet.cell(row=row, column=col).alignment = Alignment(horizontal='center') | |
status_validation.add(f'C{row}') | |
priority_validation.add(f'D{row}') | |
conditional = f'INDIRECT("C"&ROW())' | |
sheet.conditional_formatting.add(f'C{row}', | |
openpyxl.formatting.rule.FormulaRule( | |
formula=[f'{conditional}="To Do"'], | |
stopIfTrue=True, | |
fill=todo_fill)) | |
sheet.conditional_formatting.add(f'C{row}', | |
openpyxl.formatting.rule.FormulaRule( | |
formula=[f'{conditional}="In Progress"'], | |
stopIfTrue=True, | |
fill=progress_fill)) | |
sheet.conditional_formatting.add(f'C{row}', | |
openpyxl.formatting.rule.FormulaRule( | |
formula=[f'{conditional}="Blocked"'], | |
stopIfTrue=True, | |
fill=blocked_fill)) | |
sheet.conditional_formatting.add(f'C{row}', | |
openpyxl.formatting.rule.FormulaRule( | |
formula=[f'{conditional}="Done"'], | |
stopIfTrue=True, | |
fill=done_fill)) | |
sheet.conditional_formatting.add(f'B{row}:B{row}', | |
openpyxl.formatting.rule.FormulaRule( | |
formula=[f'AND(C{row}<>"",B{row}="")'], | |
stopIfTrue=True, | |
fill=mandatory_fill)) | |
sheet.conditional_formatting.add(f'C{row}:C{row}', | |
openpyxl.formatting.rule.FormulaRule( | |
formula=[f'AND(B{row}<>"",C{row}="")'], | |
stopIfTrue=True, | |
fill=mandatory_fill)) | |
sheet.conditional_formatting.add(f'E{row}:E{row}', | |
openpyxl.formatting.rule.FormulaRule( | |
formula=[f'AND(B{row}<>"",E{row}="")'], | |
stopIfTrue=True, | |
fill=mandatory_fill)) | |
def setup_weekly_dashboard(sheet, team_members, team_name, week_start_day): | |
sheet.sheet_properties.tabColor = "4F81BD" | |
title_fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid") | |
header_fill = PatternFill(start_color="DCE6F1", end_color="DCE6F1", fill_type="solid") | |
thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), | |
top=Side(style='thin'), bottom=Side(style='thin')) | |
sheet['A1'] = f"{team_name.upper()} - WEEKLY ACTIVITY" | |
sheet['A1'].font = Font(bold=True, size=16, color="FFFFFF") | |
sheet['A1'].fill = title_fill | |
sheet.merge_cells('A1:H1') | |
sheet['A1'].alignment = Alignment(horizontal='center') | |
today = datetime.now() | |
days_since_start = (today.weekday() - week_start_day) % 7 | |
start_of_week = today - timedelta(days=days_since_start) | |
weekday_names = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] | |
weekdays = [] | |
for i in range(7): | |
weekday_idx = (week_start_day + i) % 7 | |
weekdays.append(weekday_names[weekday_idx]) | |
sheet['A2'] = f"Week of {start_of_week.strftime('%Y-%m-%d')}" | |
sheet['A2'].font = Font(bold=True) | |
sheet.merge_cells('A2:H2') | |
sheet['A2'].alignment = Alignment(horizontal='center') | |
sheet.cell(row=3, column=1, value="Team Member").font = Font(bold=True) | |
sheet.cell(row=3, column=1).fill = header_fill | |
sheet.cell(row=3, column=1).border = thin_border | |
for col, day in enumerate(weekdays, 2): | |
date = start_of_week + timedelta(days=col - 2) | |
header = f"{day}\n{date.strftime('%m/%d')}" | |
cell = sheet.cell(row=3, column=col, value=header) | |
cell.font = Font(bold=True) | |
cell.fill = header_fill | |
cell.border = thin_border | |
cell.alignment = Alignment(horizontal='center', wrap_text=True) | |
sheet.column_dimensions[get_column_letter(col)].width = 12 | |
sheet.column_dimensions['A'].width = 20 | |
sheet.cell(row=3, column=9, value="Total").font = Font(bold=True) | |
sheet.cell(row=3, column=9).fill = header_fill | |
sheet.cell(row=3, column=9).border = thin_border | |
sheet.column_dimensions['I'].width = 12 | |
for row, member in enumerate(team_members, 4): | |
sheet.cell(row=row, column=1, value=member).alignment = Alignment(horizontal='left') | |
sheet.cell(row=row, column=1).border = thin_border | |
for col in range(2, 10): | |
if col < 9: | |
date = start_of_week + timedelta(days=col - 2) | |
date_str = date.strftime("%Y-%m-%d") | |
formula = f"=COUNTIFS('{member}'!F:F,\"{date_str}\",'{member}'!C:C,\"Done\")" | |
sheet.cell(row=row, column=col, value=formula) | |
else: | |
sheet.cell(row=row, column=col, value=f"=SUM(B{row}:H{row})") | |
sheet.cell(row=row, column=col).border = thin_border | |
sheet.cell(row=row, column=col).alignment = Alignment(horizontal='center') | |
total_row = len(team_members) + 4 | |
sheet.cell(row=total_row, column=1, value="DAILY TOTALS").font = Font(bold=True) | |
sheet.cell(row=total_row, column=1).border = thin_border | |
for col in range(2, 10): | |
col_letter = get_column_letter(col) | |
cell = sheet.cell(row=total_row, column=col, value=f"=SUM({col_letter}4:{col_letter}{total_row - 1})") | |
cell.font = Font(bold=True) | |
cell.border = thin_border | |
cell.alignment = Alignment(horizontal='center') | |
chart_row = total_row + 2 | |
sheet.cell(row=chart_row, column=1, value="Weekly Completion Trend").font = Font(bold=True, size=12) | |
sheet.merge_cells(f'A{chart_row}:I{chart_row}') | |
sheet.cell(row=chart_row, column=1).alignment = Alignment(horizontal='center') | |
chart = LineChart() | |
chart.title = "Tasks Completed by Day" | |
chart.x_axis.title = "Day of Week" | |
chart.y_axis.title = "Tasks Completed" | |
data = Reference(sheet, min_col=2, min_row=3, max_col=8, max_row=total_row) | |
cats = Reference(sheet, min_col=2, min_row=3, max_col=8, max_row=3) | |
chart.add_data(data, titles_from_data=False, from_rows=True) | |
chart.set_categories(cats) | |
sheet.add_chart(chart, f"A{chart_row + 2}") | |
def setup_monthly_dashboard(sheet, team_members, team_name): | |
sheet.sheet_properties.tabColor = "9BBB59" | |
title_fill = PatternFill(start_color="9BBB59", end_color="9BBB59", fill_type="solid") | |
header_fill = PatternFill(start_color="EBF1DE", end_color="EBF1DE", fill_type="solid") | |
thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), | |
top=Side(style='thin'), bottom=Side(style='thin')) | |
sheet['A1'] = f"{team_name.upper()} - MONTHLY ACTIVITY" | |
sheet['A1'].font = Font(bold=True, size=16, color="FFFFFF") | |
sheet['A1'].fill = title_fill | |
sheet.merge_cells('A1:F1') | |
sheet['A1'].alignment = Alignment(horizontal='center') | |
today = datetime.now() | |
current_month = today.strftime("%B %Y") | |
sheet['A2'] = f"Month: {current_month}" | |
sheet['A2'].font = Font(bold=True) | |
sheet.merge_cells('A2:F2') | |
sheet['A2'].alignment = Alignment(horizontal='center') | |
headers = ["Team Member", "Tasks Created", "Tasks Completed", "In Progress", "Success Rate", | |
"Average Completion Time"] | |
for col, header in enumerate(headers, 1): | |
cell = sheet.cell(row=4, column=col, value=header) | |
cell.font = Font(bold=True) | |
cell.fill = header_fill | |
cell.border = thin_border | |
cell.alignment = Alignment(horizontal='center', wrap_text=True) | |
sheet.column_dimensions[get_column_letter(col)].width = 18 | |
sheet.column_dimensions['A'].width = 20 | |
for row, member in enumerate(team_members, 5): | |
sheet.cell(row=row, column=1, value=member).alignment = Alignment(horizontal='left') | |
sheet.cell(row=row, column=1).border = thin_border | |
first_day = today.replace(day=1).strftime("%Y-%m-%d") | |
last_day = (today.replace(day=28) + timedelta(days=4)).replace(day=1) - timedelta(days=1) | |
last_day = last_day.strftime("%Y-%m-%d") | |
sheet.cell(row=row, column=2, | |
value=f"=COUNTIFS('{member}'!F:F,\">={first_day}\",'{member}'!F:F,\"<={last_day}\")") | |
sheet.cell(row=row, column=3, | |
value=f"=COUNTIFS('{member}'!C:C,\"Done\",'{member}'!F:F,\">={first_day}\",'{member}'!F:F,\"<={last_day}\")") | |
sheet.cell(row=row, column=4, | |
value=f"=COUNTIFS('{member}'!C:C,\"In Progress\",'{member}'!F:F,\">={first_day}\",'{member}'!F:F,\"<={last_day}\")") | |
sheet.cell(row=row, column=5, value=f"=IF(B{row}>0,C{row}/B{row},0)") | |
sheet.cell(row=row, column=6, value="N/A") | |
for col in range(1, 7): | |
sheet.cell(row=row, column=col).border = thin_border | |
if col == 5: | |
sheet.cell(row=row, column=col).number_format = "0.0%" | |
sheet.cell(row=row, column=col).alignment = Alignment(horizontal='center') | |
total_row = len(team_members) + 5 | |
sheet.cell(row=total_row, column=1, value="TOTALS").font = Font(bold=True) | |
sheet.cell(row=total_row, column=1).border = thin_border | |
for col in range(2, 5): | |
col_letter = get_column_letter(col) | |
cell = sheet.cell(row=total_row, column=col, value=f"=SUM({col_letter}5:{col_letter}{total_row - 1})") | |
cell.font = Font(bold=True) | |
cell.border = thin_border | |
cell.alignment = Alignment(horizontal='center') | |
sheet.cell(row=total_row, column=5, value=f"=IF(B{total_row}>0,C{total_row}/B{total_row},0)") | |
sheet.cell(row=total_row, column=5).number_format = "0.0%" | |
sheet.cell(row=total_row, column=5).font = Font(bold=True) | |
sheet.cell(row=total_row, column=5).border = thin_border | |
sheet.cell(row=total_row, column=5).alignment = Alignment(horizontal='center') | |
sheet.cell(row=total_row, column=6, value="N/A") | |
sheet.cell(row=total_row, column=6).font = Font(bold=True) | |
sheet.cell(row=total_row, column=6).border = thin_border | |
sheet.cell(row=total_row, column=6).alignment = Alignment(horizontal='center') | |
chart_row = total_row + 2 | |
sheet.cell(row=chart_row, column=1, value="Monthly Task Summary").font = Font(bold=True, size=12) | |
sheet.merge_cells(f'A{chart_row}:F{chart_row}') | |
sheet.cell(row=chart_row, column=1).alignment = Alignment(horizontal='center') | |
chart = BarChart() | |
chart.title = f"Tasks by Team Member - {current_month}" | |
chart.x_axis.title = "Team Members" | |
chart.y_axis.title = "Number of Tasks" | |
data = Reference(sheet, min_col=2, min_row=4, max_col=4, max_row=total_row - 1) | |
cats = Reference(sheet, min_col=1, min_row=5, max_row=total_row - 1) | |
chart.add_data(data, titles_from_data=True) | |
chart.set_categories(cats) | |
sheet.add_chart(chart, f"A{chart_row + 2}") | |
if __name__ == "__main__": | |
create_team_tracking_sheet() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TeamTrack
A Python script that generates a comprehensive Excel/Google Sheets compatible task tracking system with automated dashboards.
This tool creates a professional task tracking spreadsheet with individual team member boards and consolidated dashboards. It features:
Usage