document_generation.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. """Render the selected case template once and reuse stored documents."""
  2. from datetime import date, datetime
  3. from pathlib import Path
  4. from typing import Literal
  5. from zoneinfo import ZoneInfo
  6. from docxtpl import DocxTemplate
  7. from fastapi import HTTPException
  8. from sqlalchemy import text
  9. from .file_storage import get_or_create_file
  10. from .jinja_templates import number_format, templates
  11. DocumentType = Literal["Mahnung", "Rechnung", "Beitreibungsauftrag"]
  12. TEMPLATE_DIR = Path(__file__).resolve().parents[1] / "templates/forderungen/details/docs"
  13. DOCX_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
  14. def generated_document(db, client_db: str, document_no: str, document_type: DocumentType) -> Path:
  15. key = {"Client_DB": client_db, "Beleg_Nr": document_no}
  16. filename = f"{document_type}_{client_db}_{document_no}.docx"
  17. def create(destination):
  18. query = templates.env.get_template("forderungen/details/queries/forderungen_details.sql").render()
  19. row = db.execute(text(query), {"client_db": client_db, "beleg_nr": document_no}).mappings().first()
  20. if not row:
  21. raise HTTPException(404, "Forderung nicht gefunden")
  22. context = {
  23. name: value.strftime("%d.%m.%Y") if isinstance(value, (date, datetime)) else value if value is not None else ""
  24. for name, value in row.items()
  25. }
  26. for name in ("Beleg_Betrag", "Beleg_Offen", "Selbstbeteiligung_Betrag", "Mwst_Betrag"):
  27. if row.get(name) is not None:
  28. context[name] = number_format(row[name])
  29. context.update(
  30. Datum_heute=datetime.now(ZoneInfo("Europe/Berlin")).strftime("%d.%m.%Y"),
  31. Betrag_SB=context.get("Selbstbeteiligung_Betrag", ""),
  32. Betrag_USt=context.get("Mwst_Betrag", ""),
  33. Rechnung_Nr=document_no,
  34. Beleg_offen=context.get("Beleg_Offen", ""),
  35. Verursacher_Text=context.get("Verursacher_Aktuell_Text") or context.get("Verursacher_Text", ""),
  36. )
  37. template_path = TEMPLATE_DIR / f"{document_type}.docx"
  38. if not template_path.is_file():
  39. raise HTTPException(503, f"Die Vorlage {document_type}.docx ist nicht verfügbar.")
  40. document = DocxTemplate(template_path)
  41. document.render(context, autoescape=True)
  42. document.save(destination)
  43. return get_or_create_file(key, filename, create)