Mathias Claude Opus 4.5 commited on
Commit
2510bf9
·
1 Parent(s): d95fbda

Add per-month start_week support for different week numbering

Browse files

- January 2026 starts at week 2
- February 2026 starts at week 6
- Column positions remain the same, only week numbers change

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Files changed (2) hide show
  1. app.py +29 -18
  2. months_config.json +4 -2
app.py CHANGED
@@ -136,12 +136,13 @@ KNOWN_ACTIVITIES = {
136
  CONFIG_FILE = "column_config.json"
137
 
138
  # Default week configuration (fallback if config file not found)
139
- # Format: (week_number, daily_start, daily_end, target_col, percentage_col)
 
140
  DEFAULT_WEEK_CONFIGS = [
141
- (2, 3, 7, 8, 9), # Week 2: daily D-H (3-7), target I (8), pct J (9)
142
- (3, 10, 14, 15, 16), # Week 3: daily K-O (10-14), target P (15), pct Q (16)
143
- (4, 17, 21, 22, 23), # Week 4: daily R-V (17-21), target W (22), pct X (23)
144
- (5, 24, 28, 30, 31), # Week 5: daily Y-AC (24-28), target AE (30), pct AF (31) - extra empty col
145
  ]
146
 
147
  # Default monthly column configuration (fallback)
@@ -276,7 +277,7 @@ def group_rows_into_blocks(values):
276
  return blocks
277
 
278
 
279
- def process_activity_row(row, case_name, gs_name, case_data):
280
  """Process a single activity row and add data to case_data dict."""
281
  activity = get_activity(row)
282
  if not activity:
@@ -305,17 +306,21 @@ def process_activity_row(row, case_name, gs_name, case_data):
305
  # Create key for this case+gs combination
306
  key = f"{case_name}|{gs_name}"
307
 
 
 
 
 
308
  if key not in case_data:
309
  case_data[key] = {
310
  "case": case_name,
311
  "gs": gs_name,
312
- "weeks": {2: {}, 3: {}, 4: {}, 5: {}},
313
  "monthlyTotal": {"sql": 0, "sqlTarget": 0, "activity": 0, "activityTarget": 0, "sqlPctList": [], "activityPctList": []}
314
  }
315
 
316
  # Extract weekly data: actual (sum of daily), target, and percentage from sheet
317
- week_configs = get_week_configs()
318
- for week_num, daily_start, daily_end, target_col, pct_col in week_configs:
319
  actual = sum_daily(row, daily_start, daily_end)
320
  target = safe_int(row, target_col)
321
  percentage = extract_percentage(row, pct_col)
@@ -356,7 +361,7 @@ def process_activity_row(row, case_name, gs_name, case_data):
356
  case_data[key]["monthlyTotal"]["activityPctList"].append(monthly_pct)
357
 
358
 
359
- def parse_sheet_data(values):
360
  """
361
  Parse the DAILY sheet data into the format expected by the dashboard.
362
 
@@ -370,16 +375,21 @@ def parse_sheet_data(values):
370
  - Column B (1): GS/SDR name (merged - may be empty)
371
  - Column C (2): Activity type (Calls, Emails, LinkedIn, Prospects, SQL)
372
 
373
- Each week block = 5 daily columns + 1 target column + 1 percentage column:
374
- - Week 2: Cols 3-7 (daily), Col 8 (target), Col 9 (percentage)
375
- - Week 3: Cols 10-14 (daily), Col 15 (target), Col 16 (percentage)
376
- - Week 4: Cols 17-21 (daily), Col 22 (target), Col 23 (percentage)
377
- - Week 5: Cols 24-28 (daily), Col 30 (target), Col 31 (percentage) - note: col 29 empty
 
378
 
379
  Monthly totals:
380
  - Column AG (32): Monthly TARGET
381
  - Column AH (33): Monthly ACTUAL
382
  - Column AI (34): Monthly PERCENTAGE
 
 
 
 
383
  """
384
  if not values or len(values) < 5:
385
  return []
@@ -395,7 +405,7 @@ def parse_sheet_data(values):
395
  continue # Skip blocks without proper attribution
396
 
397
  for row_idx, row in block:
398
- process_activity_row(row, case_name, gs_name, case_data)
399
 
400
  # Convert to list format
401
  cases = []
@@ -547,8 +557,9 @@ async def get_data(month: str = None, source: str = None):
547
  detail=f"Failed to load data. Errors: {'; '.join(error_messages)}"
548
  )
549
 
550
- # Parse the data
551
- cases = parse_sheet_data(values)
 
552
 
553
  # Update cache
554
  _cache[cache_key] = {"data": cases, "timestamp": now, "source": actual_source}
 
136
  CONFIG_FILE = "column_config.json"
137
 
138
  # Default week configuration (fallback if config file not found)
139
+ # Format: (slot_index, daily_start, daily_end, target_col, percentage_col)
140
+ # slot_index is 0-based; actual week = start_week + slot_index
141
  DEFAULT_WEEK_CONFIGS = [
142
+ (0, 3, 7, 8, 9), # Slot 0: daily D-H (3-7), target I (8), pct J (9)
143
+ (1, 10, 14, 15, 16), # Slot 1: daily K-O (10-14), target P (15), pct Q (16)
144
+ (2, 17, 21, 22, 23), # Slot 2: daily R-V (17-21), target W (22), pct X (23)
145
+ (3, 24, 28, 30, 31), # Slot 3: daily Y-AC (24-28), target AE (30), pct AF (31) - extra empty col
146
  ]
147
 
148
  # Default monthly column configuration (fallback)
 
277
  return blocks
278
 
279
 
280
+ def process_activity_row(row, case_name, gs_name, case_data, start_week=2):
281
  """Process a single activity row and add data to case_data dict."""
282
  activity = get_activity(row)
283
  if not activity:
 
306
  # Create key for this case+gs combination
307
  key = f"{case_name}|{gs_name}"
308
 
309
+ # Calculate actual week numbers based on start_week
310
+ week_configs = get_week_configs()
311
+ week_numbers = [start_week + slot for slot, _, _, _, _ in week_configs]
312
+
313
  if key not in case_data:
314
  case_data[key] = {
315
  "case": case_name,
316
  "gs": gs_name,
317
+ "weeks": {w: {} for w in week_numbers},
318
  "monthlyTotal": {"sql": 0, "sqlTarget": 0, "activity": 0, "activityTarget": 0, "sqlPctList": [], "activityPctList": []}
319
  }
320
 
321
  # Extract weekly data: actual (sum of daily), target, and percentage from sheet
322
+ for slot, daily_start, daily_end, target_col, pct_col in week_configs:
323
+ week_num = start_week + slot
324
  actual = sum_daily(row, daily_start, daily_end)
325
  target = safe_int(row, target_col)
326
  percentage = extract_percentage(row, pct_col)
 
361
  case_data[key]["monthlyTotal"]["activityPctList"].append(monthly_pct)
362
 
363
 
364
+ def parse_sheet_data(values, start_week=2):
365
  """
366
  Parse the DAILY sheet data into the format expected by the dashboard.
367
 
 
375
  - Column B (1): GS/SDR name (merged - may be empty)
376
  - Column C (2): Activity type (Calls, Emails, LinkedIn, Prospects, SQL)
377
 
378
+ Each week block = 5 daily columns + 1 target column + 1 percentage column.
379
+ Column positions are the same each month, but week numbers vary:
380
+ - Slot 0: Cols 3-7 (daily), Col 8 (target), Col 9 (percentage)
381
+ - Slot 1: Cols 10-14 (daily), Col 15 (target), Col 16 (percentage)
382
+ - Slot 2: Cols 17-21 (daily), Col 22 (target), Col 23 (percentage)
383
+ - Slot 3: Cols 24-28 (daily), Col 30 (target), Col 31 (percentage)
384
 
385
  Monthly totals:
386
  - Column AG (32): Monthly TARGET
387
  - Column AH (33): Monthly ACTUAL
388
  - Column AI (34): Monthly PERCENTAGE
389
+
390
+ Args:
391
+ values: Raw sheet data
392
+ start_week: The first week number for this month (e.g., 2 for Jan, 6 for Feb)
393
  """
394
  if not values or len(values) < 5:
395
  return []
 
405
  continue # Skip blocks without proper attribution
406
 
407
  for row_idx, row in block:
408
+ process_activity_row(row, case_name, gs_name, case_data, start_week)
409
 
410
  # Convert to list format
411
  cases = []
 
557
  detail=f"Failed to load data. Errors: {'; '.join(error_messages)}"
558
  )
559
 
560
+ # Parse the data with month-specific start_week
561
+ start_week = month_config.get("start_week", 2)
562
+ cases = parse_sheet_data(values, start_week)
563
 
564
  # Update cache
565
  _cache[cache_key] = {"data": cases, "timestamp": now, "source": actual_source}
months_config.json CHANGED
@@ -4,13 +4,15 @@
4
  "id": "2026-01",
5
  "label": "January 2026",
6
  "sheet_id": "1af6-2KsRqeTQxdw5KVRp2WCrM6RT7HIcl70m-GgGZB4",
7
- "tab_name": "DAILY - for SDR to add data🌟"
 
8
  },
9
  {
10
  "id": "2026-02",
11
  "label": "February 2026",
12
  "sheet_id": "173_4EJ6pWjyP96d1zpZ8VasffsciCSiRLOGB_CNn7aI",
13
- "tab_name": "DAILY - for SDR to add data🌟"
 
14
  }
15
  ],
16
  "default_month": "2026-02"
 
4
  "id": "2026-01",
5
  "label": "January 2026",
6
  "sheet_id": "1af6-2KsRqeTQxdw5KVRp2WCrM6RT7HIcl70m-GgGZB4",
7
+ "tab_name": "DAILY - for SDR to add data🌟",
8
+ "start_week": 2
9
  },
10
  {
11
  "id": "2026-02",
12
  "label": "February 2026",
13
  "sheet_id": "173_4EJ6pWjyP96d1zpZ8VasffsciCSiRLOGB_CNn7aI",
14
+ "tab_name": "DAILY - for SDR to add data🌟",
15
+ "start_week": 6
16
  }
17
  ],
18
  "default_month": "2026-02"