RandomZ / app /templates /registry.py
StormShadow308's picture
- Added support for RICS survey levels (1, 2, 3) in document uploads and reports, allowing for better tier management and retrieval filtering.
b76f199
Raw
History Blame Contribute Delete
3.46 kB
"""Survey product tier → section templates, order, and export labelling.
Resolves :func:`get_template` and section order by ``Report.survey_level`` (1/2/3).
``None`` is treated as **Level 3** for template purposes (legacy reports).
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING, Final
from app.templates.rics_templates import (
LEVEL_3_DOCX_TITLE,
LEVEL_3_PRODUCT_LABEL,
SectionTemplate,
get_level3_templates,
)
from app.templates.rics_templates_l1 import (
LEVEL1_GROUP_LABELS,
LEVEL1_TEMPLATES,
LEVEL_1_DOCX_TITLE,
LEVEL_1_PRODUCT_LABEL,
)
from app.templates.rics_templates_l2 import (
LEVEL2_GROUP_LABELS,
LEVEL2_TEMPLATES,
LEVEL_2_DOCX_TITLE,
LEVEL_2_PRODUCT_LABEL,
)
from app.templates.rics_templates import GROUP_LABELS as LEVEL3_GROUP_LABELS
if TYPE_CHECKING:
pass
@dataclass(frozen=True, slots=True)
class SurveyTemplatePack:
"""All metadata needed to render and generate a report for one RICS product tier."""
level: int
product_label: str
docx_title: str
section_order: tuple[str, ...]
group_labels: dict[str, str]
_by_code: dict[str, SectionTemplate]
def get(self, code: str) -> SectionTemplate | None:
return self._by_code.get(code)
def resolve_survey_level(survey_level: int | None) -> int:
"""Map DB ``survey_level`` to a pack id. ``None`` → 3 (Building Survey / legacy)."""
if survey_level is None:
return 3
return max(1, min(3, int(survey_level)))
def _build_pack(
level: int,
product_label: str,
docx_title: str,
templates: list[SectionTemplate],
group_labels: dict[str, str],
) -> SurveyTemplatePack:
by_code = {t.code: t for t in templates}
order = tuple(t.code for t in templates)
return SurveyTemplatePack(
level=level,
product_label=product_label,
docx_title=docx_title,
section_order=order,
group_labels=dict(group_labels),
_by_code=by_code,
)
_PACK1 = _build_pack(1, LEVEL_1_PRODUCT_LABEL, LEVEL_1_DOCX_TITLE, LEVEL1_TEMPLATES, LEVEL1_GROUP_LABELS)
_PACK2 = _build_pack(2, LEVEL_2_PRODUCT_LABEL, LEVEL_2_DOCX_TITLE, LEVEL2_TEMPLATES, LEVEL2_GROUP_LABELS)
_PACK3 = _build_pack(
3,
LEVEL_3_PRODUCT_LABEL,
LEVEL_3_DOCX_TITLE,
get_level3_templates(),
LEVEL3_GROUP_LABELS,
)
_SURVEY_PACKS: Final[dict[int, SurveyTemplatePack]] = {
1: _PACK1,
2: _PACK2,
3: _PACK3,
}
def get_survey_pack(survey_level: int | None) -> SurveyTemplatePack:
"""Return the template pack for ``survey_level`` (``None`` → Level 3)."""
return _SURVEY_PACKS[resolve_survey_level(survey_level)]
def get_template(code: str, survey_level: int | None = None) -> SectionTemplate | None:
"""Resolve a section template by code and survey product tier."""
return get_survey_pack(survey_level).get(code)
def section_order_for_survey(survey_level: int | None) -> list[str]:
"""Ordered section codes for export and UI."""
return list(get_survey_pack(survey_level).section_order)
# Union of every section code ever used across packs (API validation).
ALL_VALID_SECTION_CODES: frozenset[str] = frozenset(
set(_PACK1.section_order) | set(_PACK2.section_order) | set(_PACK3.section_order)
)
# Legacy export: Level 3 order only (many tests / callers expect full BS list length).
SECTION_ORDER_LEVEL3: list[str] = list(_PACK3.section_order)