from dataclasses import dataclass from typing import Optional import openpyxl from openpyxl.styles import Alignment, Font, PatternFill from openpyxl.worksheet.worksheet import Worksheet from datatypes.magicplan.domain.models import Plan from backend.app.db.connection import db_read_session from backend.app.db.functions.magic_plan_functions import get_plan_by_uploaded_file_id UPLOADED_FILE_ID: int = 123 _HEADER_FILL = PatternFill("solid", fgColor="D9D9D9") _FLOOR_FILL = PatternFill("solid", fgColor="BDD7EE") _BOLD = Font(bold=True) _TOTAL_COLS = 31 # A–AE @dataclass class AuditRow: floor_level: Optional[int] = None # set only on floor-separator rows room_name: Optional[str] = None room_width_m: Optional[float] = None room_length_m: Optional[float] = None room_area_m2: Optional[float] = None window_label: Optional[str] = None window_location: Optional[str] = None window_width_m: Optional[float] = None window_height_m: Optional[float] = None window_area_m2: Optional[float] = None window_opening_type: Optional[str] = None door_location: Optional[str] = None door_width_mm: Optional[float] = None def _build_rows(plan: Plan) -> list[AuditRow]: rows: list[AuditRow] = [] window_counter = 1 for floor in plan.floors: rows.append(AuditRow(floor_level=floor.level)) for room in floor.rooms: n_rows = max(1, len(room.windows), len(room.doors)) for i in range(n_rows): window = room.windows[i] if i < len(room.windows) else None door = room.doors[i] if i < len(room.doors) else None row = AuditRow( room_name=room.name if i == 0 else None, room_width_m=room.width_m if i == 0 else None, room_length_m=room.length_m if i == 0 else None, room_area_m2=room.area_m2 if i == 0 else None, ) if window is not None: row.window_label = f"W{window_counter}" row.window_location = room.name row.window_width_m = window.width_m row.window_height_m = window.height_m row.window_area_m2 = window.area_m2 row.window_opening_type = window.opening_type window_counter += 1 if door is not None: row.door_location = room.name row.door_width_mm = door.width_mm rows.append(row) return rows def _write_headers(ws: Worksheet) -> None: # Row 1: group labels (merged) _merge_bold_fill(ws, 1, 1, 1, 4, "Room") # E1 blank separator _merge_bold_fill(ws, 1, 6, 1, 11, "Window Area") _merge_bold_fill(ws, 1, 12, 1, 21, "Openings") _merge_bold_fill(ws, 1, 22, 1, 26, "Trickle Vents") # AA (27) blank separator _merge_bold_fill(ws, 1, 28, 1, 31, "Door Undercuts") # Row 2: column labels _header_cell(ws, 2, 1, "Room") _header_cell(ws, 2, 2, "Width m") _header_cell(ws, 2, 3, "Length m") _header_cell(ws, 2, 4, "Area m²") _header_cell(ws, 2, 6, "Label") _header_cell(ws, 2, 7, "Location") _header_cell(ws, 2, 8, "Width m") _header_cell(ws, 2, 9, "Height m") _header_cell(ws, 2, 10, "Area m²") _header_cell(ws, 2, 11, "Opening Type") _header_cell(ws, 2, 12, "No. of Openings") for i, col in enumerate([13, 15, 17, 19]): _merge_bold_fill(ws, 2, col, 2, col + 1, f"Opening {i + 1}") _header_cell(ws, 2, 21, "Total Area m²") _header_cell(ws, 2, 22, "Blocked") _header_cell(ws, 2, 23, "Pictured") _header_cell(ws, 2, 24, "Effective Area") _header_cell(ws, 2, 25, "Count") _header_cell(ws, 2, 26, "Total Effective Area") _header_cell(ws, 2, 28, "Location") _header_cell(ws, 2, 29, "Width mm") _header_cell(ws, 2, 30, "Undercut mm") _header_cell(ws, 2, 31, "Area mm²") # Row 3: Width/Height sub-headers under Opening 1–4 for col in [13, 15, 17, 19]: _header_cell(ws, 3, col, "Width m") _header_cell(ws, 3, col + 1, "Height m") # Apply fill to all header cells in rows 1–3 for row in range(1, 4): for col in range(1, _TOTAL_COLS + 1): cell = ws.cell(row=row, column=col) cell.fill = _HEADER_FILL def _write_data_rows(ws: Worksheet, rows: list[AuditRow]) -> None: xl_row = 4 for row in rows: if row.floor_level is not None: cell = ws.cell(row=xl_row, column=1, value=f"Floor {row.floor_level}") cell.font = _BOLD cell.fill = _FLOOR_FILL ws.merge_cells( start_row=xl_row, start_column=1, end_row=xl_row, end_column=_TOTAL_COLS, ) else: ws.cell(row=xl_row, column=1, value=row.room_name) ws.cell(row=xl_row, column=2, value=row.room_width_m) ws.cell(row=xl_row, column=3, value=row.room_length_m) ws.cell(row=xl_row, column=4, value=row.room_area_m2) ws.cell(row=xl_row, column=6, value=row.window_label) ws.cell(row=xl_row, column=7, value=row.window_location) ws.cell(row=xl_row, column=8, value=row.window_width_m) ws.cell(row=xl_row, column=9, value=row.window_height_m) ws.cell(row=xl_row, column=10, value=row.window_area_m2) ws.cell(row=xl_row, column=11, value=row.window_opening_type) ws.cell(row=xl_row, column=28, value=row.door_location) ws.cell(row=xl_row, column=29, value=row.door_width_mm) xl_row += 1 def _merge_bold_fill( ws: Worksheet, r1: int, c1: int, r2: int, c2: int, value: str ) -> None: ws.merge_cells(start_row=r1, start_column=c1, end_row=r2, end_column=c2) cell = ws.cell(row=r1, column=c1, value=value) cell.font = _BOLD cell.alignment = Alignment(horizontal="center") def _header_cell(ws: Worksheet, row: int, col: int, value: str) -> None: cell = ws.cell(row=row, column=col, value=value) cell.font = _BOLD def main() -> None: with db_read_session() as session: plan: Optional[Plan] = get_plan_by_uploaded_file_id(session, UPLOADED_FILE_ID) if plan is None: raise ValueError(f"No plan found for uploaded_file_id={UPLOADED_FILE_ID}") rows = _build_rows(plan) wb = openpyxl.Workbook() ws: Worksheet = wb.active # type: ignore[assignment] ws.title = "Audit" _write_headers(ws) _write_data_rows(ws, rows) output_path = f"/tmp/magic_plan_audit_{UPLOADED_FILE_ID}.xlsx" wb.save(output_path) print(output_path) if __name__ == "__main__": main()