mesa-react / backend /app /core /anexos /generator.py
Guilherme Silberfarb Costa
alteracoes nos mapas e no carregamento de planilha
fef776b
Raw
History Blame Contribute Delete
4.18 kB
"""Gerador de documento contendo apenas anexos do modelo selecionado."""
from __future__ import annotations
import re
from datetime import datetime
from io import BytesIO
from pathlib import Path
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Cm
from .banco_dados import anexo_banco_dados_cabe_na_largura, gerar_anexo_banco_dados
from .calculo_valor import gerar_anexo_calculo
from .graficos import gerar_anexo_graficos
from .planilha_calculo import gerar_anexo_planilha
from .formatters import (
criar_paragrafo_formatado,
iniciar_secao_paisagem,
iniciar_secao_retrato,
)
from .model_data import ModelData
class AnexosGenerator:
"""Gera um DOCX com os anexos técnicos de um modelo .dai."""
def __init__(self, output_dir: Path) -> None:
self.output_dir = output_dir
def gerar(
self,
modelo: ModelData,
banco_dados_colunas: list[str] | None = None,
avaliacao: dict | None = None,
) -> Path:
doc = Document()
self._configurar_margens(doc)
self._gerar_anexos(
doc,
modelo,
banco_dados_colunas=banco_dados_colunas,
avaliacao=avaliacao,
)
self.output_dir.mkdir(parents=True, exist_ok=True)
output_path = self._gerar_nome_arquivo(modelo.nome)
doc.save(str(output_path))
return output_path
def gerar_em_memoria(
self,
modelo: ModelData,
banco_dados_colunas: list[str] | None = None,
avaliacao: dict | None = None,
) -> tuple[bytes, str]:
"""Gera o DOCX sem persistir o anexo no filesystem."""
doc = Document()
self._configurar_margens(doc)
self._gerar_anexos(
doc,
modelo,
banco_dados_colunas=banco_dados_colunas,
avaliacao=avaliacao,
)
buffer = BytesIO()
doc.save(buffer)
return buffer.getvalue(), self._gerar_nome_arquivo(modelo.nome).name
def _configurar_margens(self, doc: Document) -> None:
for section in doc.sections:
section.top_margin = Cm(2.5)
section.bottom_margin = Cm(2.5)
section.left_margin = Cm(3)
section.right_margin = Cm(2)
def _criar_titulo_anexo(self, doc: Document, titulo: str) -> None:
criar_paragrafo_formatado(
doc,
titulo,
negrito=True,
sublinhado=True,
tamanho=10,
espaco_antes=18,
espaco_depois=12,
alinhamento=WD_ALIGN_PARAGRAPH.CENTER,
)
def _largura_util_secao_atual(self, doc: Document) -> int:
section = doc.sections[-1]
return int(section.page_width - section.left_margin - section.right_margin)
def _gerar_anexos(
self,
doc: Document,
modelo: ModelData,
banco_dados_colunas: list[str] | None = None,
avaliacao: dict | None = None,
) -> None:
banco_cabe_em_retrato = anexo_banco_dados_cabe_na_largura(
modelo,
banco_dados_colunas,
self._largura_util_secao_atual(doc),
)
if not banco_cabe_em_retrato:
iniciar_secao_paisagem(doc)
self._criar_titulo_anexo(doc, "ANEXO I - BANCO DE DADOS")
gerar_anexo_banco_dados(doc, modelo, colunas=banco_dados_colunas)
iniciar_secao_retrato(doc)
self._criar_titulo_anexo(
doc,
"ANEXO II - PLANILHA DE CÁLCULO E RESULTADOS ESTATÍSTICOS",
)
gerar_anexo_planilha(doc, modelo)
doc.add_page_break()
self._criar_titulo_anexo(doc, "ANEXO III - GRÁFICOS")
gerar_anexo_graficos(doc, modelo)
doc.add_page_break()
self._criar_titulo_anexo(doc, "ANEXO IV - CÁLCULO DO VALOR")
gerar_anexo_calculo(doc, modelo, avaliacao=avaliacao)
def _gerar_nome_arquivo(self, modelo_nome: str) -> Path:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
modelo_safe = re.sub(r"[^\w\-]", "_", modelo_nome)
return self.output_dir / f"Anexos_{modelo_safe}_{timestamp}.docx"