Files
Odoo-Modules/fusion_claims/models/email_builder_mixin.py
2026-02-22 01:22:18 -05:00

243 lines
8.9 KiB
Python

# -*- coding: utf-8 -*-
# Fusion Claims - Professional Email Builder Mixin
# Provides consistent, dark/light mode safe email templates across all modules.
from odoo import models
class FusionEmailBuilderMixin(models.AbstractModel):
_name = 'fusion.email.builder.mixin'
_description = 'Fusion Email Builder Mixin'
# ------------------------------------------------------------------
# Color constants
# ------------------------------------------------------------------
_EMAIL_COLORS = {
'info': '#2B6CB0',
'success': '#38a169',
'attention': '#d69e2e',
'urgent': '#c53030',
}
# ------------------------------------------------------------------
# Public API
# ------------------------------------------------------------------
def _email_build(
self,
title,
summary,
sections=None,
note=None,
note_color=None,
email_type='info',
attachments_note=None,
button_url=None,
button_text='View Case Details',
sender_name=None,
extra_html='',
):
"""Build a complete professional email HTML string.
Args:
title: Email heading (e.g. "Application Approved")
summary: One-sentence summary HTML (may contain <strong> tags)
sections: list of (heading, rows) where rows is list of (label, value)
e.g. [('Case Details', [('Client', 'John'), ('Case', 'S30073')])]
note: Optional note/next-steps text (plain or HTML)
note_color: Override left-border color for note (default uses email_type)
email_type: 'info' | 'success' | 'attention' | 'urgent'
attachments_note: Optional string listing attached files
button_url: Optional CTA button URL
button_text: CTA button label
sender_name: Name for sign-off (defaults to current user)
extra_html: Any additional HTML to insert before sign-off
"""
accent = self._EMAIL_COLORS.get(email_type, self._EMAIL_COLORS['info'])
company = self._get_company_info()
parts = []
# -- Wrapper open + accent bar
parts.append(
f'<div style="font-family:-apple-system,BlinkMacSystemFont,\'Segoe UI\',Roboto,Arial,sans-serif;'
f'max-width:600px;margin:0 auto;color:#2d3748;">'
f'<div style="height:4px;background-color:{accent};"></div>'
f'<div style="background:#ffffff;padding:32px 28px;border:1px solid #e2e8f0;border-top:none;">'
)
# -- Company name
parts.append(
f'<p style="color:{accent};font-size:13px;font-weight:600;letter-spacing:0.5px;'
f'text-transform:uppercase;margin:0 0 24px 0;">{company["name"]}</p>'
)
# -- Title
parts.append(
f'<h2 style="color:#1a202c;font-size:22px;font-weight:700;'
f'margin:0 0 6px 0;line-height:1.3;">{title}</h2>'
)
# -- Summary
parts.append(
f'<p style="color:#718096;font-size:15px;line-height:1.5;'
f'margin:0 0 24px 0;">{summary}</p>'
)
# -- Sections (details tables)
if sections:
for heading, rows in sections:
parts.append(self._email_section(heading, rows))
# -- Note / Next Steps
if note:
nc = note_color or accent
parts.append(self._email_note(note, nc))
# -- Extra HTML
if extra_html:
parts.append(extra_html)
# -- Attachment note
if attachments_note:
parts.append(self._email_attachment_note(attachments_note))
# -- CTA Button
if button_url:
parts.append(self._email_button(button_url, button_text, accent))
# -- Sign-off
signer = sender_name or (self.env.user.name if self.env.user else '')
parts.append(
f'<p style="color:#2d3748;font-size:14px;line-height:1.6;margin:24px 0 0 0;">'
f'Best regards,<br/>'
f'<strong>{signer}</strong><br/>'
f'<span style="color:#718096;">{company["name"]}</span></p>'
)
# -- Close content card
parts.append('</div>')
# -- Footer
footer_parts = [company['name']]
if company['phone']:
footer_parts.append(company['phone'])
if company['email']:
footer_parts.append(company['email'])
footer_text = ' &middot; '.join(footer_parts)
parts.append(
f'<div style="padding:16px 28px;text-align:center;">'
f'<p style="color:#a0aec0;font-size:11px;line-height:1.5;margin:0;">'
f'{footer_text}<br/>'
f'This is an automated notification from the ADP Claims Management System.</p>'
f'</div>'
)
# -- Close wrapper
parts.append('</div>')
return ''.join(parts)
# ------------------------------------------------------------------
# Building blocks
# ------------------------------------------------------------------
def _email_section(self, heading, rows):
"""Build a labeled details table section.
Args:
heading: Section title (e.g. "Case Details")
rows: list of (label, value) tuples. Value can be plain text or HTML.
"""
if not rows:
return ''
html = (
'<table style="width:100%;border-collapse:collapse;margin:0 0 24px 0;">'
f'<tr><td colspan="2" style="padding:10px 14px;font-size:12px;font-weight:600;'
f'color:#718096;text-transform:uppercase;letter-spacing:0.5px;'
f'border-bottom:2px solid #e2e8f0;">{heading}</td></tr>'
)
for label, value in rows:
if value is None or value == '' or value is False:
continue
html += (
f'<tr>'
f'<td style="padding:10px 14px;color:#718096;font-size:14px;'
f'border-bottom:1px solid #f0f0f0;width:35%;">{label}</td>'
f'<td style="padding:10px 14px;color:#2d3748;font-size:14px;'
f'border-bottom:1px solid #f0f0f0;">{value}</td>'
f'</tr>'
)
html += '</table>'
return html
def _email_note(self, text, color='#2B6CB0'):
"""Build a left-border accent note block."""
return (
f'<div style="border-left:3px solid {color};padding:12px 16px;'
f'margin:0 0 24px 0;background:#f7fafc;">'
f'<p style="margin:0;font-size:14px;line-height:1.5;color:#2d3748;">{text}</p>'
f'</div>'
)
def _email_button(self, url, text='View Case Details', color='#2B6CB0'):
"""Build a centered CTA button."""
return (
f'<p style="text-align:center;margin:28px 0;">'
f'<a href="{url}" style="display:inline-block;background:{color};color:#ffffff;'
f'padding:12px 28px;text-decoration:none;border-radius:6px;'
f'font-size:14px;font-weight:600;">{text}</a></p>'
)
def _email_attachment_note(self, description):
"""Build a dashed-border attachment callout.
Args:
description: e.g. "ADP Application (PDF), XML Data File"
"""
return (
f'<div style="padding:10px 14px;border:1px dashed #e2e8f0;border-radius:6px;'
f'margin:0 0 24px 0;">'
f'<p style="margin:0;font-size:13px;color:#718096;">'
f'<strong style="color:#2d3748;">Attached:</strong> {description}</p>'
f'</div>'
)
def _email_status_badge(self, label, color='#2B6CB0'):
"""Return an inline status badge/pill HTML snippet."""
# Pick a light background tint for the badge
bg_map = {
'#38a169': '#f0fff4',
'#2B6CB0': '#ebf4ff',
'#d69e2e': '#fefcbf',
'#c53030': '#fff5f5',
}
bg = bg_map.get(color, '#ebf4ff')
return (
f'<span style="display:inline-block;background:{bg};color:{color};'
f'padding:2px 10px;border-radius:12px;font-size:12px;font-weight:600;">'
f'{label}</span>'
)
# ------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------
def _get_company_info(self):
"""Return company name, phone, email for email templates."""
company = getattr(self, 'company_id', None) or self.env.company
return {
'name': company.name or 'Our Company',
'phone': company.phone or '',
'email': company.email or '',
}
def _email_is_enabled(self):
"""Check if email notifications are enabled in settings."""
ICP = self.env['ir.config_parameter'].sudo()
val = ICP.get_param('fusion_claims.enable_email_notifications', 'True')
return val.lower() in ('true', '1', 'yes')