File size: 3,131 Bytes
2c59485
 
 
 
 
5fbc76a
28b188b
5fbc76a
2c59485
5fbc76a
 
7c75767
9f9b802
2c59485
5fbc76a
 
 
 
a07d7fa
5fbc76a
 
 
 
 
2c59485
28b188b
9f9b802
2c59485
28b188b
5fbc76a
2c59485
9f9b802
 
2c59485
 
5fbc76a
28b188b
 
5fbc76a
 
 
 
28b188b
5fbc76a
 
 
2c59485
 
 
5fbc76a
2c59485
5fbc76a
2c59485
 
7c75767
 
5fbc76a
7c75767
5fbc76a
7c75767
 
 
 
5fbc76a
7c75767
 
 
5fbc76a
7c75767
 
5fbc76a
 
7c75767
 
 
 
5fbc76a
 
 
 
 
 
 
9f9b802
7c75767
 
2c59485
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt

def process_data(df):
    # Clean and prepare data
    df = df[['Project Category', 'Logged']].copy()
    df = df.dropna(subset=['Project Category'])
    
    # Consolidate categories
    df['Main Category'] = df['Project Category'].apply(
        lambda x: 'Billable' if 'Billable' in str(x) else str(x).strip()
    )
    
    # Group by main categories
    main_categories = df.groupby('Main Category')['Logged'].sum().reset_index()
    total_hours = main_categories['Logged'].sum()
    main_categories['Percentage'] = (main_categories['Logged'] / total_hours * 100).round(1)
    
    # Prepare non-billable breakdown
    non_billable = df[df['Main Category'] == 'Non-Billable']
    non_billable_breakdown = non_billable.groupby('Project Category')['Logged'].sum().reset_index()
    
    return main_categories, non_billable_breakdown

def create_pie_chart(data):
    fig, ax = plt.subplots(figsize=(6, 6))
    wedges, texts, autotexts = ax.pie(
        data['Logged'],
        labels=data['Main Category'],
        autopct='%1.1f%%',
        colors=['#4CAF50', '#FFC107', '#9E9E9E'],
        startangle=90
    )
    plt.setp(autotexts, size=10, weight="bold", color='white')
    ax.set_title('Overall Utilization Distribution', pad=20)
    return fig

def create_bar_chart(data):
    fig, ax = plt.subplots(figsize=(10, 5))
    data.plot(kind='bar', x='Project Category', y='Logged', ax=ax, legend=False)
    ax.set_title('Non-Billable Time Breakdown')
    ax.set_ylabel('Hours')
    ax.set_xlabel('')
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()
    return fig

def main():
    st.title('QA Team Utilization Dashboard')
    
    uploaded_file = st.file_uploader("Upload Timesheet Excel File", type=['xls', 'xlsx'])
    
    if uploaded_file:
        try:
            df = pd.read_excel(uploaded_file, sheet_name='Report')
            main_cats, non_billable = process_data(df)
            
            # Main utilization section
            st.header("Overall Utilization")
            col1, col2 = st.columns([2, 1])
            
            with col1:
                st.pyplot(create_pie_chart(main_cats))
            
            with col2:
                st.dataframe(
                    main_cats[['Main Category', 'Logged', 'Percentage']],
                    hide_index=True,
                    column_config={
                        'Main Category': 'Category',
                        'Logged': st.column_config.NumberColumn('Hours', format="%.2f"),
                        'Percentage': st.column_config.NumberColumn(format="%.1f%%")
                    }
                )
            
            # Non-billable breakdown
            st.header("Non-Billable Detailed Breakdown")
            st.pyplot(create_bar_chart(non_billable))
            
            # Raw data preview
            st.subheader("Raw Data Preview")
            st.dataframe(df.head(10), hide_index=True)
            
        except Exception as e:
            st.error(f"Error processing file: {str(e)}")

if __name__ == "__main__":
    main()