Spaces:
Runtime error
Runtime error
Mathias commited on
Commit ·
2bc6b2a
1
Parent(s): fe91a8b
Fix parser to handle DAILY sheet structure with activity rows
Browse files
app.py
CHANGED
|
@@ -47,69 +47,117 @@ def get_sheets_service():
|
|
| 47 |
|
| 48 |
def parse_sheet_data(values):
|
| 49 |
"""
|
| 50 |
-
Parse the
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
"""
|
| 53 |
-
if not values or len(values) <
|
| 54 |
return []
|
| 55 |
|
| 56 |
-
#
|
| 57 |
-
|
| 58 |
-
|
| 59 |
|
| 60 |
-
#
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
col_map[h.lower().strip()] = i
|
| 65 |
|
| 66 |
-
for row_idx, row in enumerate(values
|
| 67 |
-
if
|
|
|
|
|
|
|
| 68 |
continue
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
if not case_name or not gs_name:
|
| 76 |
-
continue
|
| 77 |
-
|
| 78 |
-
# Build weeks data
|
| 79 |
-
weeks = {}
|
| 80 |
-
for week_num in [2, 3, 4, 5]:
|
| 81 |
-
week_key = f"w{week_num}"
|
| 82 |
-
weeks[week_num] = {
|
| 83 |
-
"sql": safe_int(row, col_map.get(f"{week_key}_sql")),
|
| 84 |
-
"sqlTarget": safe_int(row, col_map.get(f"{week_key}_sqltarget")),
|
| 85 |
-
"calls": safe_int(row, col_map.get(f"{week_key}_calls")),
|
| 86 |
-
"callsTarget": safe_int(row, col_map.get(f"{week_key}_callstarget")),
|
| 87 |
-
"emails": safe_int(row, col_map.get(f"{week_key}_emails")),
|
| 88 |
-
"emailsTarget": safe_int(row, col_map.get(f"{week_key}_emailstarget")),
|
| 89 |
-
"linkedin": safe_int(row, col_map.get(f"{week_key}_linkedin")),
|
| 90 |
-
"linkedinTarget": safe_int(row, col_map.get(f"{week_key}_linkedintarget")),
|
| 91 |
-
}
|
| 92 |
-
|
| 93 |
-
# Monthly totals
|
| 94 |
-
monthly_total = {
|
| 95 |
-
"sql": safe_int(row, col_map.get("monthly_sql")),
|
| 96 |
-
"sqlTarget": safe_int(row, col_map.get("monthly_sqltarget")),
|
| 97 |
-
"activity": safe_int(row, col_map.get("monthly_activity")),
|
| 98 |
-
"activityTarget": safe_int(row, col_map.get("monthly_activitytarget")),
|
| 99 |
-
}
|
| 100 |
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
"monthlyTotal": monthly_total
|
| 107 |
-
})
|
| 108 |
|
| 109 |
-
|
| 110 |
-
print(f"Error parsing row {row_idx}: {e}")
|
| 111 |
continue
|
| 112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
return cases
|
| 114 |
|
| 115 |
|
|
|
|
| 47 |
|
| 48 |
def parse_sheet_data(values):
|
| 49 |
"""
|
| 50 |
+
Parse the DAILY sheet data into the format expected by the dashboard.
|
| 51 |
+
|
| 52 |
+
DAILY sheet structure:
|
| 53 |
+
- Column A: Case name (may be empty for continuation rows)
|
| 54 |
+
- Column B: GS/SDR name (may be empty for continuation rows)
|
| 55 |
+
- Column C: Activity type (Calls, Emails, LinkedIn, Prospects, Discovery, SQL)
|
| 56 |
+
- Columns D-H: Week 2 daily data (M, T, W, T, F)
|
| 57 |
+
- Column I: Week 2 total
|
| 58 |
+
- Column J: Week 2 percentage
|
| 59 |
+
- Columns K-O: Week 3 daily data
|
| 60 |
+
- Column P: Week 3 total
|
| 61 |
+
- Column Q: Week 3 percentage
|
| 62 |
+
- And so on for Week 4, Week 5...
|
| 63 |
"""
|
| 64 |
+
if not values or len(values) < 5:
|
| 65 |
return []
|
| 66 |
|
| 67 |
+
# Find week columns by looking at header rows
|
| 68 |
+
# Row 1 has week labels, Row 4 has day labels (M, T, W, T, F)
|
| 69 |
+
# Data starts from row 5
|
| 70 |
|
| 71 |
+
# Build a map of case+gs -> activity data
|
| 72 |
+
case_data = {}
|
| 73 |
+
current_case = None
|
| 74 |
+
current_gs = None
|
|
|
|
| 75 |
|
| 76 |
+
for row_idx, row in enumerate(values):
|
| 77 |
+
if row_idx < 4: # Skip header rows
|
| 78 |
+
continue
|
| 79 |
+
if not row or len(row) < 3:
|
| 80 |
continue
|
| 81 |
|
| 82 |
+
# Column A: Case, Column B: GS, Column C: Activity
|
| 83 |
+
case_name = row[0].strip() if len(row) > 0 and row[0] else None
|
| 84 |
+
gs_name = row[1].strip() if len(row) > 1 and row[1] else None
|
| 85 |
+
activity = row[2].strip() if len(row) > 2 and row[2] else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
+
# Update current case/gs if provided
|
| 88 |
+
if case_name:
|
| 89 |
+
current_case = case_name
|
| 90 |
+
if gs_name:
|
| 91 |
+
current_gs = gs_name
|
|
|
|
|
|
|
| 92 |
|
| 93 |
+
if not current_case or not current_gs or not activity:
|
|
|
|
| 94 |
continue
|
| 95 |
|
| 96 |
+
# Create key for this case+gs combination
|
| 97 |
+
key = f"{current_case}|{current_gs}"
|
| 98 |
+
|
| 99 |
+
if key not in case_data:
|
| 100 |
+
case_data[key] = {
|
| 101 |
+
"case": current_case,
|
| 102 |
+
"gs": current_gs,
|
| 103 |
+
"weeks": {2: {}, 3: {}, 4: {}, 5: {}},
|
| 104 |
+
"monthlyTotal": {"sql": 0, "sqlTarget": 0, "activity": 0, "activityTarget": 0}
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
# Map activity types to our data structure
|
| 108 |
+
activity_lower = activity.lower()
|
| 109 |
+
activity_map = {
|
| 110 |
+
"calls": "calls",
|
| 111 |
+
"emails": "emails",
|
| 112 |
+
"linkedin": "linkedin",
|
| 113 |
+
"prospects": "prospects",
|
| 114 |
+
"prospects (activated)": "prospects",
|
| 115 |
+
"discovery": "discovery",
|
| 116 |
+
"sql": "sql"
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
activity_key = activity_map.get(activity_lower)
|
| 120 |
+
if not activity_key:
|
| 121 |
+
continue
|
| 122 |
+
|
| 123 |
+
# Week column positions (0-indexed):
|
| 124 |
+
# Week 2: D-H (3-7) daily, I (8) total
|
| 125 |
+
# Week 3: K-O (10-14) daily, P (15) total
|
| 126 |
+
# Week 4: R-V (17-21) daily, W (22) total
|
| 127 |
+
# Week 5: Y-AC (24-28) daily, AD (29) total
|
| 128 |
+
week_configs = [
|
| 129 |
+
(2, 8), # Week 2 total in column I (index 8)
|
| 130 |
+
(3, 15), # Week 3 total in column P (index 15)
|
| 131 |
+
(4, 22), # Week 4 total in column W (index 22)
|
| 132 |
+
(5, 29), # Week 5 total in column AD (index 29)
|
| 133 |
+
]
|
| 134 |
+
|
| 135 |
+
for week_num, total_col in week_configs:
|
| 136 |
+
total_val = safe_int(row, total_col)
|
| 137 |
+
if week_num not in case_data[key]["weeks"]:
|
| 138 |
+
case_data[key]["weeks"][week_num] = {}
|
| 139 |
+
case_data[key]["weeks"][week_num][activity_key] = total_val
|
| 140 |
+
case_data[key]["weeks"][week_num][f"{activity_key}Target"] = 0 # Targets not in this sheet
|
| 141 |
+
|
| 142 |
+
# Add to monthly total
|
| 143 |
+
if activity_key == "sql":
|
| 144 |
+
for week_num, total_col in week_configs:
|
| 145 |
+
case_data[key]["monthlyTotal"]["sql"] += safe_int(row, total_col)
|
| 146 |
+
elif activity_key in ["calls", "emails", "linkedin", "prospects"]:
|
| 147 |
+
for week_num, total_col in week_configs:
|
| 148 |
+
case_data[key]["monthlyTotal"]["activity"] += safe_int(row, total_col)
|
| 149 |
+
|
| 150 |
+
# Convert to list format
|
| 151 |
+
cases = []
|
| 152 |
+
for idx, (key, data) in enumerate(case_data.items()):
|
| 153 |
+
cases.append({
|
| 154 |
+
"id": idx + 1,
|
| 155 |
+
"case": data["case"],
|
| 156 |
+
"gs": data["gs"],
|
| 157 |
+
"weeks": data["weeks"],
|
| 158 |
+
"monthlyTotal": data["monthlyTotal"]
|
| 159 |
+
})
|
| 160 |
+
|
| 161 |
return cases
|
| 162 |
|
| 163 |
|