HR-ATS-Portal/backend/offer_email_template/template.py

108 lines
4.6 KiB
Python

from html import escape
def _text(value):
"""Escape user-entered text and keep its line breaks ("Maymar Office\\nOr\\nHead Office")."""
if value in (None, ""):
return ""
return "<br>".join(escape(line.strip()) for line in str(value).splitlines())
def _salary(value):
if value in (None, ""):
return ""
try:
amount = float(str(value).replace(",", ""))
return f"PKR {amount:,.0f}"
except (TypeError, ValueError):
return _text(value)
def _recruiter_names(recruiter_names):
names = [str(n).strip() for n in (recruiter_names or []) if n and str(n).strip()]
if not names:
return ""
if len(names) == 1:
return escape(names[0])
if len(names) == 2:
return f"{escape(names[0])} &amp; {escape(names[1])}"
return ", ".join(escape(n) for n in names[:-1]) + f" &amp; {escape(names[-1])}"
def _package_row(label, value, bold=False, widths=(174, 449), bold_label=False, valign="top"):
cell = f"border:1px solid #000000;padding:1px 4px;vertical-align:{valign};"
shown = f"<strong>{value}</strong>" if bold else value
label = f"<strong>{label}</strong>" if bold_label else label
return (
"<tr>"
f'<td width="{widths[0]}" style="width:{widths[0]}px;{cell}">{label}</td>'
f'<td width="{widths[1]}" style="width:{widths[1]}px;{cell}">{shown}</td>'
"</tr>"
)
def render_offer_email_subject(candidate_name, offered_position, company_name):
"""Offer Intent <Candidate Name> - <Designation> <Entity Name>"""
name = str(candidate_name or "").strip()
position = str(offered_position or "").strip()
company = str(company_name or "").strip()
return f"Offer Intent {name} - {position} {company}".strip()
def render_offer_email_body(
candidate_name,
offered_position,
cadre,
company_name,
monthly_gross_salary,
subsidized_services,
probation_period,
notice_period,
location,
timings,
recruiter_names,
):
"""Annexure J - Offer format to be sent to the candidate, as an Outlook-safe
HTML body: inline styles and a bordered table only, no <style> block or
classes (Outlook strips them). Arial in grey and the bold runs match the PDF;
the offer letter itself goes out as an attachment. recruiter_names is a list,
joined as "A", "A & B" or "A, B & C"."""
font = "font-family:Arial,Helvetica,sans-serif;font-size:11pt;color:#595959;"
table_font = "font-family:Arial,Helvetica,sans-serif;font-size:11pt;color:#7F7F7F;"
paragraph = "margin:0 0 11pt 0;"
first_name = (str(candidate_name or "").strip().split() or [""])[0]
rows = (
_package_row("Monthly Gross Salary", _salary(monthly_gross_salary), bold=True)
+ _package_row("Subsidized Services", _text(subsidized_services), valign="middle")
+ _package_row("Probation Period", _text(probation_period), valign="middle")
+ _package_row("Notice Period", _text(notice_period), valign="middle")
+ _package_row("Location", _text(location), valign="middle")
+ _package_row("Timings", _text(timings), valign="middle")
)
return (
f'<div style="{font}">'
f'<p style="{paragraph}">Dear {escape(first_name)},</p>'
f'<p style="{paragraph}">Hope this email finds you well.</p>'
f'<p style="{paragraph}">Subsequent to your interviews and pursuant to our discussion, '
f"we are pleased to offer you the role of <strong>{_text(offered_position)}</strong> "
f"in <strong>{_text(cadre)}</strong> Cadre with <strong>{_text(company_name)}</strong>, "
f"based at {_text(' '.join(str(location or '').split()))}.</p>"
f'<p style="{paragraph}">As discussed, the details of the remuneration package are as follows:</p>'
'<table cellpadding="0" cellspacing="0" border="1" width="623" '
f'style="width:623px;border-collapse:collapse;border:1px solid #000000;{table_font}margin:0 0 11pt 0;">'
f"{rows}"
"</table>"
f'<p style="{paragraph}">You will also be eligible for all the benefits at your grade '
"as per the Company&rsquo;s policy.</p>"
f'<p style="{paragraph}">Also attached in the email is the offer letter. Please sign the attached '
"offer letter as your acceptance within 24 hours, mentioning your "
"<strong>suggested date for joining.</strong></p>"
f'<p style="{paragraph}text-align:justify;">We look forward to the opportunity to work with you '
"in an atmosphere that is mutually challenging and rewarding.</p>"
f'<p style="{paragraph}">Regards,</p>'
f'<p style="margin:0;">{_recruiter_names(recruiter_names)}</p>'
"</div>"
)