HH/apps/accounts/pdf_service.py

281 lines
10 KiB
Python

"""
PDF generation service for acknowledgements
"""
from io import BytesIO
from datetime import datetime
from django.conf import settings
from django.utils import translation
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, Image
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
class AcknowledgementPDFService:
"""Service for generating PDF documents for acknowledgements"""
@staticmethod
def generate_pdf(user, acknowledgement, language='en'):
"""
Generate PDF for a user acknowledgement
Args:
user: User instance
acknowledgement: UserAcknowledgement instance
language: Language code ('en' or 'ar')
Returns:
BytesIO object containing PDF data
"""
# Set language for translation
translation.activate(language)
# Create buffer
buffer = BytesIO()
# Create PDF document
doc = SimpleDocTemplate(
buffer,
pagesize=A4,
rightMargin=72,
leftMargin=72,
topMargin=72,
bottomMargin=18
)
# Build content
story = []
styles = getSampleStyleSheet()
# Custom styles
title_style = ParagraphStyle(
'CustomTitle',
parent=styles['Heading1'],
fontSize=24,
textColor=colors.HexColor('#2c3e50'),
spaceAfter=30,
alignment=TA_CENTER
)
subtitle_style = ParagraphStyle(
'CustomSubtitle',
parent=styles['Heading2'],
fontSize=16,
textColor=colors.HexColor('#3498db'),
spaceAfter=20
)
body_style = ParagraphStyle(
'CustomBody',
parent=styles['BodyText'],
fontSize=11,
spaceAfter=12,
leading=16
)
heading_style = ParagraphStyle(
'CustomHeading',
parent=styles['Heading3'],
fontSize=14,
textColor=colors.HexColor('#2c3e50'),
spaceAfter=10,
spaceBefore=20
)
# Title
if language == 'ar':
title = "إقرار الاستلام والتوقيع"
else:
title = "Acknowledgement Receipt"
story.append(Paragraph(title, title_style))
story.append(Spacer(1, 0.2*inch))
# Header line
header_data = [
('Date', 'التاريخ'),
('Employee Name', 'اسم الموظف'),
('Employee ID', 'رقم الموظف'),
('Email', 'البريد الإلكتروني'),
]
user_data = [
(acknowledgement.acknowledged_at.strftime('%Y-%m-%d %H:%M:%S')),
(user.get_full_name()),
(user.employee_id or 'N/A'),
(user.email),
]
# Create header table
header_table_data = []
for i, (label_en, label_ar) in enumerate(header_data):
if language == 'ar':
header_table_data.append([
Paragraph(f"<b>{label_ar}:</b>", body_style),
Paragraph(user_data[i], body_style)
])
else:
header_table_data.append([
Paragraph(f"<b>{label_en}:</b>", body_style),
Paragraph(user_data[i], body_style)
])
header_table = Table(header_table_data, colWidths=[2*inch, 3*inch])
header_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (0, -1), colors.HexColor('#f8f9fa')),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
('TOPPADDING', (0, 0), (-1, -1), 8),
('BOTTOMPADDING', (0, 0), (-1, -1), 8),
]))
story.append(header_table)
story.append(Spacer(1, 0.3*inch))
# Acknowledgement details
story.append(Paragraph(
"Acknowledgement Details" if language == 'en' else "تفاصيل الإقرار",
subtitle_style
))
# Get checklist item text based on language
checklist_item = acknowledgement.checklist_item
if language == 'ar' and checklist_item.text_ar:
item_text = checklist_item.text_ar
else:
item_text = checklist_item.text_en
if language == 'ar' and checklist_item.description_ar:
item_desc = checklist_item.description_ar
else:
item_desc = checklist_item.description_en or checklist_item.description_en
# Item details
item_details = [
('Acknowledgement Code', 'رمز الإقرار', checklist_item.code),
('Acknowledgement Item', 'بند الإقرار', item_text),
]
if item_desc:
item_details.append(('Description', 'الوصف', item_desc))
if checklist_item.content:
if language == 'ar' and checklist_item.content.title_ar:
content_title = checklist_item.content.title_ar
else:
content_title = checklist_item.content.title_en
item_details.append(('Section', 'القسم', content_title))
# Create item table
item_table_data = []
for label_en, label_ar, value in item_details:
if language == 'ar':
item_table_data.append([
Paragraph(f"<b>{label_ar}:</b>", body_style),
Paragraph(value, body_style)
])
else:
item_table_data.append([
Paragraph(f"<b>{label_en}:</b>", body_style),
Paragraph(value, body_style)
])
item_table = Table(item_table_data, colWidths=[2*inch, 4*inch])
item_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (0, -1), colors.HexColor('#e8f4f8')),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
('TOPPADDING', (0, 0), (-1, -1), 8),
('BOTTOMPADDING', (0, 0), (-1, -1), 8),
]))
story.append(item_table)
story.append(Spacer(1, 0.3*inch))
# Signature section
story.append(Paragraph(
"Digital Signature" if language == 'en' else "التوقيع الرقمي",
heading_style
))
signature_text = (
"This acknowledgement was digitally signed by the employee above."
if language == 'en'
else "تم توقيع هذا الإقرار رقميًا بواسطة الموظف المذكور أعلاه."
)
story.append(Paragraph(signature_text, body_style))
story.append(Spacer(1, 0.1*inch))
# IP and User Agent
if acknowledgement.signature_ip:
ip_text = f"IP Address: {acknowledgement.signature_ip}" if language == 'en' else f"عنوان IP: {acknowledgement.signature_ip}"
story.append(Paragraph(f"<b>{ip_text}</b>", body_style))
if acknowledgement.signature_user_agent:
ua_text = f"Device: {acknowledgement.signature_user_agent[:100]}..." if language == 'en' else f"الجهاز: {acknowledgement.signature_user_agent[:100]}..."
story.append(Paragraph(f"<b>{ua_text}</b>", body_style))
story.append(Spacer(1, 0.5*inch))
# Declaration
declaration_text_en = (
"I hereby acknowledge that I have read and understood the above acknowledgement "
"and agree to comply with all policies and procedures outlined therein. "
"I understand that this is a legally binding document."
)
declaration_text_ar = (
"أقر هنا بأنني قرأت وفهمت الإقرار المذكور أعلاه وأوافق على الامتثال لجميع "
"السياسات والإجراءات المنصوص عليها فيه. أفهم أن هذا وثيقة ملزمة قانونيًا."
)
declaration = declaration_text_ar if language == 'ar' else declaration_text_en
story.append(Paragraph(f"<i>{declaration}</i>", body_style))
story.append(Spacer(1, 1.5*inch))
# Signature line
signature_label = "Digital Signature" if language == 'en' else "التوقيع الرقمي"
story.append(Paragraph(f"<b>{signature_label}</b>", body_style))
story.append(Spacer(1, 0.2*inch))
# Add signature image if available
if acknowledgement.signature:
try:
from base64 import b64decode
sig_data = b64decode(acknowledgement.signature)
sig_buffer = BytesIO(sig_data)
sig_image = Image(sig_buffer, width=2*inch, height=1*inch)
story.append(sig_image)
except:
pass
# Footer
story.append(Spacer(1, 0.5*inch))
footer_text = (
f"Generated by PX360 Patient Experience Management System on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
if language == 'en'
else f"تم الإنشاء بواسطة نظام إدارة تجربة المريض PX360 في {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
)
footer_style = ParagraphStyle(
'CustomFooter',
parent=styles['BodyText'],
fontSize=9,
textColor=colors.grey,
alignment=TA_CENTER
)
story.append(Paragraph(footer_text, footer_style))
# Build PDF
doc.build(story)
# Get PDF value
pdf_value = buffer.getvalue()
buffer.close()
return pdf_value