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>
This commit is contained in:
parent
71723dcaf4
commit
74cd93fede
@ -1,10 +1,17 @@
|
||||
# === 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
|
||||
from xhtml2pdf import pisa
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def render_to_pdf(template_src, context_dict=None):
|
||||
@ -21,6 +28,17 @@ def render_to_pdf(template_src, context_dict=None):
|
||||
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)
|
||||
|
||||
@ -22,7 +22,9 @@ from django.conf import settings
|
||||
|
||||
from .models import Worker, Project, WorkLog, Team, PayrollRecord, Loan, PayrollAdjustment
|
||||
from .forms import AttendanceLogForm, PayrollAdjustmentForm
|
||||
from .utils import render_to_pdf
|
||||
# NOTE: render_to_pdf is NOT imported here at the top level.
|
||||
# It's imported lazily inside process_payment() to avoid crashing the
|
||||
# entire app if xhtml2pdf is not installed on the server.
|
||||
|
||||
|
||||
# === PAYROLL CONSTANTS ===
|
||||
@ -812,6 +814,10 @@ def process_payment(request, worker_id):
|
||||
# EMAIL PAYSLIP (outside the transaction — if email fails, payment is
|
||||
# still saved. We don't want a network error to roll back a real payment.)
|
||||
# =========================================================================
|
||||
|
||||
# Lazy import — avoids crashing the app if xhtml2pdf isn't installed
|
||||
from .utils import render_to_pdf
|
||||
|
||||
subject = f"Payslip for {worker.name} - {payroll_record.date}"
|
||||
|
||||
# Context for both the HTML email body and the PDF attachment
|
||||
@ -827,7 +833,7 @@ def process_payment(request, worker_id):
|
||||
html_message = render_to_string('core/email/payslip_email.html', email_context)
|
||||
plain_message = strip_tags(html_message)
|
||||
|
||||
# 2. Render PDF attachment
|
||||
# 2. Render PDF attachment (returns None if xhtml2pdf is not installed)
|
||||
pdf_content = render_to_pdf('core/pdf/payslip_pdf.html', email_context)
|
||||
|
||||
# 3. Send email with PDF attached
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user