- core/utils.py: render_to_pdf() wrapper for xhtml2pdf - core/templates/core/pdf/payslip_pdf.html: A4 PDF payslip (matches V2 layout) - core/templates/core/email/payslip_email.html: HTML email body for Spark - core/templates/core/payslip.html: browser payslip detail page with print - core/views.py: add payslip_detail view, wire email+PDF into process_payment - core/urls.py: add payroll/payslip/<pk>/ route - config/settings.py: add SPARK_RECEIPT_EMAIL setting - payroll_dashboard.html: add "View" payslip link in Payment History tab All templates show adjustments (bonuses, deductions, overtime, loan repayments) as line items. Amounts always show 2 decimal places. Email failure does not roll back payment — handled gracefully with warning message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
35 lines
946 B
Python
35 lines
946 B
Python
# === PDF GENERATION ===
|
|
# Converts a Django HTML template into a PDF file using xhtml2pdf.
|
|
# Used for payslip and receipt PDF attachments sent via email.
|
|
|
|
from io import BytesIO
|
|
from django.template.loader import get_template
|
|
from xhtml2pdf import pisa
|
|
|
|
|
|
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 = {}
|
|
|
|
# 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
|