From 48ce9c0eab5717c618b512522c4de9182d173345 Mon Sep 17 00:00:00 2001 From: rangelbruno Date: Thu, 5 Feb 2026 10:57:17 -0300 Subject: [PATCH] =?UTF-8?q?Feat(Mat=C3=A9ria):=20Adiciona=20cabe=C3=A7alho?= =?UTF-8?q?=20com=20identifica=C3=A7=C3=A3o=20no=20documento?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adiciona automaticamente o cabeçalho com tipo, número e ano no início do documento da matéria legislativa após o recebimento da proposição. Ex: "INDICAÇÃO 10 / 2026" --- sapl/materia/forms.py | 6 +++ sapl/utils_template.py | 85 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index a102c9e4f..7a86cfc7d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -43,6 +43,7 @@ from sapl.utils import (autor_label, autor_modal, timing, SEPARADOR_HASH_PROPOSICAO, validar_arquivo, YES_NO_CHOICES, GoogleRecapthaMixin, get_client_ip) +from sapl.utils_template import adicionar_cabecalho_materia from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, DocumentoAcessorio, Numeracao, @@ -2650,6 +2651,11 @@ class ConfirmarProposicaoForm(ProposicaoForm): materia.save() conteudo_gerado = materia + # Adiciona cabeçalho com identificação da matéria no documento + # Ex: "INDICAÇÃO 10 / 2026" + if proposicao.texto_original: + adicionar_cabecalho_materia(materia) + if proposicao.texto_articulado.exists(): ta = proposicao.texto_articulado.first() ta_materia = ta.clone_for(materia) diff --git a/sapl/utils_template.py b/sapl/utils_template.py index 49d60486b..4fee76918 100644 --- a/sapl/utils_template.py +++ b/sapl/utils_template.py @@ -3,8 +3,11 @@ Utilitários para aplicar templates de documentos aos novos documentos criados via OnlyOffice. """ import logging +import os from io import BytesIO +from django.core.files.base import ContentFile + logger = logging.getLogger(__name__) @@ -223,3 +226,85 @@ def aplicar_template_existente(documento_path, tipo_conteudo, tipo_especifico=No except Exception as e: logger.error(f"Erro ao aplicar template a documento existente: {e}") return None + + +def adicionar_cabecalho_materia(materia): + """ + Adiciona cabeçalho com identificação da matéria no início do documento. + + Adiciona um parágrafo no início do documento com o formato: + "TIPO NÚMERO / ANO" (ex: "INDICAÇÃO 10 / 2026") + + Args: + materia: objeto MateriaLegislativa com texto_original preenchido + + Returns: + True se o cabeçalho foi adicionado com sucesso, False caso contrário + """ + if not materia.texto_original: + logger.warning(f"Matéria {materia.pk} não possui texto_original") + return False + + # Verifica se é um arquivo .docx + arquivo_path = materia.texto_original.path + extensao = os.path.splitext(arquivo_path)[1].lower() + + if extensao not in ['.docx', '.doc']: + logger.info(f"Arquivo {arquivo_path} não é .docx, pulando adição de cabeçalho") + return False + + try: + from docx import Document + from docx.shared import Pt, Inches + from docx.enum.text import WD_ALIGN_PARAGRAPH + + # Carrega o documento + doc = Document(arquivo_path) + + # Monta o texto do cabeçalho: "TIPO NÚMERO / ANO" + tipo_nome = str(materia.tipo).upper() + cabecalho_texto = f"{tipo_nome} {materia.numero} / {materia.ano}" + + # Insere o cabeçalho no início do documento + # Precisamos inserir antes do primeiro parágrafo + if doc.paragraphs: + primeiro_paragrafo = doc.paragraphs[0] + + # Cria novo parágrafo antes do primeiro + novo_paragrafo = primeiro_paragrafo.insert_paragraph_before(cabecalho_texto) + + # Formata o cabeçalho + novo_paragrafo.alignment = WD_ALIGN_PARAGRAPH.CENTER + for run in novo_paragrafo.runs: + run.bold = True + run.font.size = Pt(14) + + # Adiciona linha em branco após o cabeçalho + primeiro_paragrafo.insert_paragraph_before('') + else: + # Documento vazio, adiciona o cabeçalho como primeiro parágrafo + paragrafo = doc.add_paragraph(cabecalho_texto) + paragrafo.alignment = WD_ALIGN_PARAGRAPH.CENTER + for run in paragrafo.runs: + run.bold = True + run.font.size = Pt(14) + doc.add_paragraph('') + + # Salva o documento modificado + file_stream = BytesIO() + doc.save(file_stream) + file_stream.seek(0) + + # Atualiza o arquivo da matéria + nome_arquivo = os.path.basename(arquivo_path) + materia.texto_original.save(nome_arquivo, ContentFile(file_stream.read()), save=True) + + logger.info(f"Cabeçalho adicionado à matéria {materia.pk}: {cabecalho_texto}") + return True + + except ImportError: + logger.error("python-docx não está instalado") + return False + except Exception as e: + logger.error(f"Erro ao adicionar cabeçalho à matéria {materia.pk}: {e}") + return False