Add platform SMTP and firm wizard invite email
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from __future__ import annotations
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, datetime, timedelta
|
||||
@@ -19,6 +19,7 @@ from app.modules.core.rbac.models import Role, UserRole
|
||||
from app.modules.core.tenancy.models import Branch, FinancialYear, Tenant
|
||||
from app.modules.core.tenancy.settings_models import BranchSettings
|
||||
from app.modules.employees.models import Employee
|
||||
from app.modules.email_integration.services import send_platform_user_invite_email
|
||||
|
||||
|
||||
class FirmWizardError(ValueError):
|
||||
@@ -33,6 +34,8 @@ class FirmWizardResult:
|
||||
financial_year: FinancialYear | None
|
||||
invite_url: str
|
||||
invite_token: str
|
||||
invite_email_status: str | None = None
|
||||
invite_email_error: str | None = None
|
||||
|
||||
|
||||
def normalize_code(value: str, *, upper: bool = True) -> str:
|
||||
@@ -202,6 +205,19 @@ def validate_firm_wizard_payload(db: Session, payload: dict[str, Any]) -> list[s
|
||||
return errors
|
||||
|
||||
|
||||
|
||||
def safe_employee_code_for_firm_admin(db: Session, tenant_id: int, tenant_code: str, user_id: int) -> str:
|
||||
base = normalize_code(f"{tenant_code}_ADMIN_{user_id}")[:50]
|
||||
employee_code = base
|
||||
suffix = 1
|
||||
while db.execute(
|
||||
select(Employee).where(Employee.tenant_id == tenant_id, Employee.employee_code == employee_code)
|
||||
).scalar_one_or_none():
|
||||
suffix += 1
|
||||
employee_code = f"{base[:44]}_{suffix}"[:50]
|
||||
return employee_code
|
||||
|
||||
|
||||
def _hash_token(token: str) -> str:
|
||||
return hashlib.sha256(token.encode("utf-8")).hexdigest()
|
||||
|
||||
@@ -295,14 +311,11 @@ def create_firm_from_wizard(db: Session, payload: dict[str, Any]) -> FirmWizardR
|
||||
db.flush()
|
||||
db.add(UserRole(user_id=firm_admin.id, role_id=role.id))
|
||||
|
||||
# Auto-create and link Employee Master for the primary Firm Admin.
|
||||
# Employee Portal requires employees.user_id to match the logged-in user.
|
||||
employee_code = normalize_code(f"{payload['tenant_code']}_ADMIN")[:50]
|
||||
firm_admin_employee = Employee(
|
||||
tenant_id=tenant.id,
|
||||
branch_id=branch.id,
|
||||
user_id=firm_admin.id,
|
||||
employee_code=employee_code,
|
||||
employee_code=safe_employee_code_for_firm_admin(db, tenant.id, tenant.code, firm_admin.id),
|
||||
full_name=payload["admin_full_name"],
|
||||
email=payload["admin_email"],
|
||||
mobile=payload["admin_mobile"] or None,
|
||||
@@ -338,6 +351,23 @@ def create_firm_from_wizard(db: Session, payload: dict[str, Any]) -> FirmWizardR
|
||||
invite_token = create_invite_token_without_commit(db, firm_admin)
|
||||
invite_url = public_invite_url(invite_token)
|
||||
|
||||
invite_email_status = None
|
||||
invite_email_error = None
|
||||
try:
|
||||
invite_email_log = send_platform_user_invite_email(
|
||||
db,
|
||||
user=firm_admin,
|
||||
invite_token=invite_token,
|
||||
firm_name=tenant.display_name or tenant.name,
|
||||
)
|
||||
if invite_email_log:
|
||||
invite_email_status = invite_email_log.status
|
||||
invite_email_error = invite_email_log.error_message
|
||||
except Exception as exc:
|
||||
# Firm creation must not fail only because SMTP is unavailable.
|
||||
invite_email_status = "FAILED"
|
||||
invite_email_error = str(exc)
|
||||
|
||||
return FirmWizardResult(
|
||||
tenant=tenant,
|
||||
branch=branch,
|
||||
@@ -345,5 +375,6 @@ def create_firm_from_wizard(db: Session, payload: dict[str, Any]) -> FirmWizardR
|
||||
financial_year=financial_year,
|
||||
invite_url=invite_url,
|
||||
invite_token=invite_token,
|
||||
invite_email_status=invite_email_status,
|
||||
invite_email_error=invite_email_error,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user