#!/usr/bin/env python3 """Generate Excel export from saved schedule using template.""" import json import sys import openpyxl from openpyxl.styles import PatternFill from copy import copy TEMPLATE = sys.argv[1] SCHEDULE = sys.argv[2] OUTPUT = sys.argv[3] STATION_ROWS = { 'DE': 13, 'HR': 14, 'MA': 15, 'ST': 16, 'MSA': 17, 'MUA': 18, 'NM': 19, 'FL': 20, 'JP': 21, 'ZL': 22, 'SN': 23, 'AN': 24, 'KN': 25, 'NA': 26, 'MSB': 27, 'NR': 28, 'FRB': 29, 'KR': 30, 'KC': 31, 'VY': 32, 'IP': 33, 'MUC': 34, 'HN': 35, 'FRC': 36, 'VL': 37, 'NH': 38, 'KB': 39, } NO_FILL = PatternFill(fill_type=None) with open(SCHEDULE) as f: raw = json.load(f) data = raw['data'] if 'data' in raw and 'stations' not in raw else raw wb = openpyxl.load_workbook(TEMPLATE) ws = wb.active # Identify weekend columns: DEN row (row 11) has fill on weekends/holidays # Capture the DATA ROW fill (row 13) for those columns — it has the correct theme=0 gray weekend_cols = set() for col in range(7, 281): den_cell = ws.cell(row=11, column=col) if den_cell.fill and den_cell.fill.fill_type == 'solid': weekend_cols.add(col) col_fills = {} for col in weekend_cols: data_cell = ws.cell(row=13, column=col) if data_cell.fill and data_cell.fill.fill_type == 'solid': theme = data_cell.fill.fgColor.theme if hasattr(data_cell.fill.fgColor, 'theme') and isinstance(data_cell.fill.fgColor.theme, int) else None if theme == 0: # Gray weekend fill, not teal s/v fill col_fills[col] = copy(data_cell.fill) for station in data['stations']: row = STATION_ROWS.get(station['code']) if not row: continue # Step 1: Clear all values for col in range(7, 281): ws.cell(row=row, column=col).value = None # Step 2: Restore original column fills (weekends etc) for col in range(7, 281): if col in col_fills: ws.cell(row=row, column=col).fill = copy(col_fills[col]) else: ws.cell(row=row, column=col).fill = NO_FILL # Step 3: Write data values (no extra fills — only weekend column fills from step 2) for idx_str, cell_data in station['data'].items(): idx = int(idx_str) col = idx + 7 if col < 7 or col > 280: continue val = cell_data.get('v') if val is not None: ws.cell(row=row, column=col).value = val # Add DEN row comments if 'dayComments' in data: comments = data['dayComments'] # Handle both list format [{dayIdx, text}] and dict format {"idx": "text"} if isinstance(comments, list): for c in comments: idx = c.get('dayIdx', 0) text = c.get('text', '') if text: col = idx + 7 if 7 <= col <= 280: from openpyxl.comments import Comment ws.cell(row=11, column=col).comment = Comment(text, 'Metro HMG') elif isinstance(comments, dict): for idx_str, text in comments.items(): if text: col = int(idx_str) + 7 if 7 <= col <= 280: from openpyxl.comments import Comment ws.cell(row=11, column=col).comment = Comment(text, 'Metro HMG') # Add cell comments (per station+day) if 'cellComments' in data: from openpyxl.comments import Comment as XlComment for c in data.get('cellComments', []): code = c.get('stationCode', '') idx = c.get('dayIdx', 0) text = c.get('text', '') row = STATION_ROWS.get(code) if row and text: col = idx + 7 if 7 <= col <= 280: ws.cell(row=row, column=col).comment = XlComment(text, 'Metro HMG') wb.save(OUTPUT) print(f'Exported to {OUTPUT}', file=sys.stderr)