From 8821a7943bc5a6049cd741b76db99dddeb75b92b Mon Sep 17 00:00:00 2001 From: Md Bayazid Bostame Date: Thu, 26 Mar 2026 14:13:03 +0100 Subject: [PATCH] snapshot: preserve company config integration and pdf cleanup --- .../media/templates/offboarding_template.html | 1 + .../templates/onboarding_intro_template.html | 1 + .../media/templates/onboarding_template.html | 1 + backend/workflows/branding.py | 40 ++++++++++++++++++- backend/workflows/tasks.py | 38 ++++++++++++++++-- 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/backend/media/templates/offboarding_template.html b/backend/media/templates/offboarding_template.html index af585a6..6b3ee37 100644 --- a/backend/media/templates/offboarding_template.html +++ b/backend/media/templates/offboarding_template.html @@ -151,6 +151,7 @@ .manual-grid td { width: 50%; } + diff --git a/backend/media/templates/onboarding_intro_template.html b/backend/media/templates/onboarding_intro_template.html index 8be677a..5e4639a 100644 --- a/backend/media/templates/onboarding_intro_template.html +++ b/backend/media/templates/onboarding_intro_template.html @@ -134,6 +134,7 @@ vertical-align: bottom; margin: 0 6px; } + diff --git a/backend/media/templates/onboarding_template.html b/backend/media/templates/onboarding_template.html index 273619e..5807195 100644 --- a/backend/media/templates/onboarding_template.html +++ b/backend/media/templates/onboarding_template.html @@ -125,6 +125,7 @@ .muted-cell { color: #64748b; } + diff --git a/backend/workflows/branding.py b/backend/workflows/branding.py index 94c2022..a4300e3 100644 --- a/backend/workflows/branding.py +++ b/backend/workflows/branding.py @@ -149,6 +149,43 @@ def get_branding_email_copy() -> dict[str, str]: } +def get_company_contact_copy() -> dict[str, str]: + branding = get_portal_branding() + company_config = get_portal_company_config() + company_name = (branding.company_name or 'TUBCO').strip() + legal_name = (company_config.legal_company_name or company_name).strip() + domain = get_company_email_domain() + support_email = (branding.support_email or '').strip() + it_contact_email = (company_config.it_contact_email or support_email or f'it@{domain}').strip() + hr_contact_email = (company_config.hr_contact_email or support_email or f'hr@{domain}').strip() + operations_contact_email = (company_config.operations_contact_email or support_email or f'info@{domain}').strip() + address_parts = [ + (company_config.street_address or '').strip(), + ' '.join(part for part in [(company_config.postal_code or '').strip(), (company_config.city or '').strip()] if part).strip(), + (company_config.country or '').strip(), + ] + address = ', '.join(part for part in address_parts if part) + return { + 'company_name': company_name, + 'legal_company_name': legal_name, + 'support_email': support_email, + 'it_contact_email': it_contact_email, + 'hr_contact_email': hr_contact_email, + 'operations_contact_email': operations_contact_email, + 'phone_number': (company_config.phone_number or '').strip(), + 'website_url': (company_config.website_url or '').strip(), + 'imprint_url': (company_config.imprint_url or '').strip(), + 'privacy_url': (company_config.privacy_url or '').strip(), + 'address': address, + 'street_address': (company_config.street_address or '').strip(), + 'postal_code': (company_config.postal_code or '').strip(), + 'city': (company_config.city or '').strip(), + 'country': (company_config.country or '').strip(), + 'registration_number': (company_config.registration_number or '').strip(), + 'vat_id': (company_config.vat_id or '').strip(), + } + + def get_branded_from_email(email_address: str | None) -> str | None: address = (email_address or '').strip() if not address: @@ -166,8 +203,9 @@ def get_default_notification_templates() -> dict[str, dict[str, str]]: templates = deepcopy(DEFAULT_NOTIFICATION_TEMPLATES) branding_copy = get_branding_email_copy() + company_contact = get_company_contact_copy() company_name = branding_copy['company_name'] - support_email = branding_copy['support_email'] or f"it@{branding_copy['company_domain']}" + support_email = company_contact['it_contact_email'] or branding_copy['support_email'] or f"it@{branding_copy['company_domain']}" welcome = templates.get('onboarding_welcome') if welcome: welcome['subject'] = f'Willkommen bei {company_name}, {{ VORNAME }}' diff --git a/backend/workflows/tasks.py b/backend/workflows/tasks.py index 9adfd4b..238efcb 100644 --- a/backend/workflows/tasks.py +++ b/backend/workflows/tasks.py @@ -13,7 +13,7 @@ from jinja2 import Template from pypdf import PageObject, PdfReader, PdfWriter from xhtml2pdf import pisa -from .branding import get_default_notification_templates, get_portal_letterhead_path +from .branding import get_company_contact_copy, get_default_notification_templates, get_portal_letterhead_path from .models import EmployeeProfile, IntroChecklistItem, NotificationRule, NotificationTemplate, OffboardingRequest, OnboardingIntroductionSession, OnboardingRequest, ScheduledWelcomeEmail, WorkflowConfig from .emailing import send_system_email from .services import upload_to_nextcloud @@ -867,6 +867,7 @@ def _generate_onboarding_pdf(request_obj: OnboardingRequest) -> Path: template_path = settings.PDF_TEMPLATES_DIR / 'onboarding_template.html' letterhead_path = get_portal_letterhead_path() + company_contact = get_company_contact_copy() devices = _split_multiline(request_obj.needed_devices) software = _split_multiline(request_obj.needed_software) @@ -980,6 +981,11 @@ def _generate_onboarding_pdf(request_obj: OnboardingRequest) -> Path: 'UNTERSCHRIFT_HINWEIS': signature_note, 'REQUESTED_BY_NAME': requester_name, 'REQUESTED_BY_EMAIL': requester_email, + 'COMPANY_LEGAL_NAME': company_contact['legal_company_name'] or company_contact['company_name'], + 'COMPANY_ADDRESS': company_contact['address'] or t['not_available_short'], + 'COMPANY_IT_CONTACT': company_contact['it_contact_email'] or t['not_available_short'], + 'COMPANY_HR_CONTACT': company_contact['hr_contact_email'] or t['not_available_short'], + 'COMPANY_PHONE': company_contact['phone_number'] or t['not_available_short'], } html = _render_html(template_path, context) @@ -1000,6 +1006,7 @@ def _generate_onboarding_intro_pdf(request_obj: OnboardingRequest, language_code template_path = settings.PDF_TEMPLATES_DIR / 'onboarding_intro_template.html' letterhead_path = get_portal_letterhead_path() + company_contact = get_company_contact_copy() salutation = (request_obj.get_gender_display() or '').strip() display_name = f"{salutation} {request_obj.full_name}".strip() if salutation else request_obj.full_name @@ -1024,6 +1031,11 @@ def _generate_onboarding_intro_pdf(request_obj: OnboardingRequest, language_code 'REQUESTED_BY_NAME': requester_name, 'REQUESTED_BY_EMAIL': requester_email, 'INTRO_SECTIONS': intro_sections, + 'COMPANY_LEGAL_NAME': company_contact['legal_company_name'] or company_contact['company_name'], + 'COMPANY_ADDRESS': company_contact['address'] or t['not_available_short'], + 'COMPANY_IT_CONTACT': company_contact['it_contact_email'] or t['not_available_short'], + 'COMPANY_HR_CONTACT': company_contact['hr_contact_email'] or t['not_available_short'], + 'COMPANY_PHONE': company_contact['phone_number'] or t['not_available_short'], } html = _render_html(template_path, context) @@ -1050,6 +1062,7 @@ def _generate_onboarding_intro_session_pdf( template_path = settings.PDF_TEMPLATES_DIR / 'onboarding_intro_session_pdf.html' letterhead_path = get_portal_letterhead_path() + company_contact = get_company_contact_copy() salutation = (request_obj.get_gender_display() or '').strip() display_name = f"{salutation} {request_obj.full_name}".strip() if salutation else request_obj.full_name @@ -1091,6 +1104,11 @@ def _generate_onboarding_intro_session_pdf( 'SESSION_UPDATED_AT': session.updated_at, 'SESSION_NOTES': session.notes or t['not_available_short'], 'INTRO_SECTIONS': exported_sections, + 'COMPANY_LEGAL_NAME': company_contact['legal_company_name'] or company_contact['company_name'], + 'COMPANY_ADDRESS': company_contact['address'] or t['not_available_short'], + 'COMPANY_IT_CONTACT': company_contact['it_contact_email'] or t['not_available_short'], + 'COMPANY_HR_CONTACT': company_contact['hr_contact_email'] or t['not_available_short'], + 'COMPANY_PHONE': company_contact['phone_number'] or t['not_available_short'], } html = _render_html(template_path, context) @@ -1111,6 +1129,7 @@ def _generate_offboarding_pdf(request_obj: OffboardingRequest) -> Path: template_path = settings.PDF_TEMPLATES_DIR / 'offboarding_template.html' letterhead_path = get_portal_letterhead_path() + company_contact = get_company_contact_copy() latest_onboarding = ( OnboardingRequest.objects.filter(work_email=request_obj.work_email) .order_by('-created_at') @@ -1158,6 +1177,11 @@ def _generate_offboarding_pdf(request_obj: OffboardingRequest) -> Path: 'MANUAL_RESOURCES': _chunk_choice_labels(RESOURCE_CHOICES), 'MANUAL_EXTRA_HARDWARE': _chunk_choice_labels(HARDWARE_EXTRA_CHOICES), 'MANUAL_EXTRA_SOFTWARE': _chunk_choice_labels(SOFTWARE_EXTRA_CHOICES), + 'COMPANY_LEGAL_NAME': company_contact['legal_company_name'] or company_contact['company_name'], + 'COMPANY_ADDRESS': company_contact['address'] or t['not_available_short'], + 'COMPANY_IT_CONTACT': company_contact['it_contact_email'] or t['not_available_short'], + 'COMPANY_HR_CONTACT': company_contact['hr_contact_email'] or t['not_available_short'], + 'COMPANY_PHONE': company_contact['phone_number'] or t['not_available_short'], } html = _render_html(template_path, context) @@ -1177,6 +1201,7 @@ def process_onboarding_request(onboarding_request_id: int) -> None: request_obj.save(update_fields=['processing_status', 'last_error']) try: branding_copy = get_branding_email_copy() + company_contact = get_company_contact_copy() it_email, general_info_email, business_card_email, hr_works_email, key_email = _resolve_workflow_emails() salutation = (request_obj.get_gender_display() or '').strip() display_name = f"{salutation} {request_obj.full_name}".strip() @@ -1205,7 +1230,10 @@ def process_onboarding_request(onboarding_request_id: int) -> None: 'CONTRACT_START': request_obj.contract_start, 'EMAIL': request_obj.work_email, 'REQUESTED_BY': request_obj.onboarded_by_email or '-', - 'SUPPORT_EMAIL': branding_copy['support_email'] or f"it@{branding_copy['company_domain']}", + 'SUPPORT_EMAIL': company_contact['it_contact_email'] or branding_copy['support_email'] or f"it@{branding_copy['company_domain']}", + 'IT_CONTACT_EMAIL': company_contact['it_contact_email'], + 'HR_CONTACT_EMAIL': company_contact['hr_contact_email'], + 'OPERATIONS_CONTACT_EMAIL': company_contact['operations_contact_email'], 'BUSINESS_CARD_NAME': request_obj.business_card_name or display_name, 'BUSINESS_CARD_TITLE': request_obj.business_card_title or '-', 'BUSINESS_CARD_EMAIL': request_obj.business_card_email or request_obj.work_email, @@ -1288,6 +1316,7 @@ def process_offboarding_request(offboarding_request_id: int) -> None: request_obj.save(update_fields=['processing_status', 'last_error']) try: branding_copy = get_branding_email_copy() + company_contact = get_company_contact_copy() it_email, general_info_email, _, hr_works_email, _ = _resolve_workflow_emails() pdf_path = _generate_offboarding_pdf(request_obj) @@ -1300,7 +1329,10 @@ def process_offboarding_request(offboarding_request_id: int) -> None: 'LAST_WORKING_DAY': request_obj.last_working_day, 'REQUESTED_BY': request_obj.requested_by_email, 'EMAIL': request_obj.work_email, - 'SUPPORT_EMAIL': branding_copy['support_email'] or f"it@{branding_copy['company_domain']}", + 'SUPPORT_EMAIL': company_contact['it_contact_email'] or branding_copy['support_email'] or f"it@{branding_copy['company_domain']}", + 'IT_CONTACT_EMAIL': company_contact['it_contact_email'], + 'HR_CONTACT_EMAIL': company_contact['hr_contact_email'], + 'OPERATIONS_CONTACT_EMAIL': company_contact['operations_contact_email'], } _send_templated_email(