38686-vm/core/utils.py
Konrad du Plessis 74cd93fede Fix 503: make xhtml2pdf import lazy to prevent app crash
If xhtml2pdf fails to install on Flatlogic's server (missing C
libraries), the top-level import crashed the entire WSGI app.
Now it imports lazily inside render_to_pdf() so the app starts
even without xhtml2pdf — only PDF generation degrades gracefully.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 21:07:33 +02:00

53 lines
1.6 KiB
Python

# === PDF GENERATION ===
# Converts a Django HTML template into a PDF file using xhtml2pdf.
# Used for payslip and receipt PDF attachments sent via email.
#
# IMPORTANT: xhtml2pdf is imported LAZILY (inside the function, not at the
# top of the file). This is intentional — if xhtml2pdf fails to install on
# the server (missing C libraries), the rest of the app still works.
# Only PDF generation will fail gracefully.
import logging
from io import BytesIO
from django.template.loader import get_template
logger = logging.getLogger(__name__)
def render_to_pdf(template_src, context_dict=None):
"""
Render a Django template to PDF bytes.
Args:
template_src: Path to the template (e.g. 'core/pdf/payslip_pdf.html')
context_dict: Template context variables
Returns:
PDF content as bytes, or None if there was an error.
"""
if context_dict is None:
context_dict = {}
# --- Lazy import: only load xhtml2pdf when actually generating a PDF ---
# This prevents the entire app from crashing if xhtml2pdf isn't installed.
try:
from xhtml2pdf import pisa
except ImportError:
logger.error(
"xhtml2pdf is not installed — cannot generate PDF. "
"Install it with: pip install xhtml2pdf"
)
return None
# Load and render the HTML template
template = get_template(template_src)
html = template.render(context_dict)
# Convert HTML to PDF
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result)
if not pdf.err:
return result.getvalue()
return None