"""Document generation service via docxtpl (.docx + Jinja2).""" from __future__ import annotations import io from datetime import datetime from pathlib import Path from docxtpl import DocxTemplate from loguru import logger from app.models.tech_stack import DocumentRequest TEMPLATES_DIR = Path(__file__).resolve().parents[2] / "templates" class DocumentEngine: """Render .docx templates with supplied context.""" SUPPORTED = { "act_hidden_works": "act_hidden_works.docx", "act_osmotr_responsibility": "act_osmotr_responsibility.docx", "general_work_log": "general_work_log.docx", "material_certificate": "material_certificate.docx", } def render(self, request: DocumentRequest) -> bytes: template_file = self.SUPPORTED.get(request.template_name) if template_file is None: raise ValueError( f"Unknown template: {request.template_name}. " f"Supported: {list(self.SUPPORTED)}" ) template_path = TEMPLATES_DIR / template_file if not template_path.exists(): raise FileNotFoundError( f"Template file not found: {template_path}" ) logger.info(f"Rendering document: {request.template_name}") tpl = DocxTemplate(str(template_path)) context = { "generated_at": datetime.utcnow().strftime("%d.%m.%Y %H:%M"), "project_id": request.project_id, **request.context, } tpl.render(context) buf = io.BytesIO() tpl.save(buf) buf.seek(0) return buf.read() def get_document_engine() -> DocumentEngine: return DocumentEngine()