Allow staff email correction and sync linked login email

This commit is contained in:
A R R R Associates
2026-09-03 15:29:08 +05:30
parent 9068b523bc
commit eef9a01365
2 changed files with 69 additions and 2 deletions
+64 -1
View File
@@ -13,6 +13,7 @@ from sqlalchemy.orm import Session, selectinload
from app.core.security.passwords import hash_password
from app.modules.core.iam.models import User
from app.modules.core.audit.service import write_audit_log
from app.modules.alerts.service import create_alert
from app.modules.alerts.workflow_escalations import create_workflow_escalation
from app.modules.core.iam.scope import build_scope, list_visible_branches, list_visible_tenants, validate_branch_matches_tenant
@@ -421,6 +422,7 @@ def update_employee(db: Session, actor: User, emp: Employee, data: dict[str, Any
raise HTTPException(status_code=400, detail="Employee code and full name are required.")
user_id = cleaned.get("user_id")
linked_user: User | None = None
if user_id:
linked_user = db.get(User, int(user_id))
if not linked_user:
@@ -433,6 +435,46 @@ def update_employee(db: Session, actor: User, emp: Employee, data: dict[str, Any
_ensure_unique(db, tenant_id=emp.tenant_id, employee_code=employee_code, user_id=user_id, exclude_id=emp.id)
old_email = (emp.email or "").strip().lower()
requested_email = (cleaned.get("email") or "").strip().lower()
email_changed = requested_email != old_email
if email_changed:
actor_roles = _role_set(db, actor)
if not actor_roles.intersection({"System Admin", "Firm Admin", "Partner"}):
raise HTTPException(
status_code=403,
detail="Only a Firm Admin or Partner can correct an employee email address.",
)
if linked_user is not None and not requested_email:
raise HTTPException(
status_code=400,
detail="Email cannot be blank while the employee is linked to a login user.",
)
if requested_email:
duplicate_user_stmt = select(User).where(func.lower(User.email) == requested_email)
if linked_user is not None:
duplicate_user_stmt = duplicate_user_stmt.where(User.id != linked_user.id)
duplicate_user = db.execute(duplicate_user_stmt).scalar_one_or_none()
if duplicate_user:
raise HTTPException(status_code=409, detail="This email address is already used by another login user.")
duplicate_employee = db.execute(
select(Employee).where(
Employee.tenant_id == emp.tenant_id,
Employee.id != emp.id,
func.lower(Employee.email) == requested_email,
)
).scalar_one_or_none()
if duplicate_employee:
raise HTTPException(status_code=409, detail="This email address is already used by another employee in this firm.")
cleaned["email"] = requested_email or None
if linked_user is not None:
linked_user.email = requested_email
update_fields = [
"employee_code", "full_name", "email", "mobile", "alternate_mobile", "date_of_joining", "date_of_leaving",
"employment_type", "status", "is_active", "department", "designation", "reporting_manager_user_id",
@@ -447,7 +489,28 @@ def update_employee(db: Session, actor: User, emp: Employee, data: dict[str, Any
emp.updated_by_user_id = actor.id
emp.updated_at_utc = datetime.now(timezone.utc)
_disable_relieved_employee_login(db, emp)
db.commit()
db.flush()
if email_changed:
write_audit_log(
db,
action="employee.email.corrected",
entity_type="employee",
actor=actor,
entity_id=emp.id,
entity_name=emp.full_name,
target_tenant_id=emp.tenant_id,
target_branch_id=emp.branch_id,
details={
"old_email": old_email or None,
"new_email": requested_email or None,
"linked_user_id": linked_user.id if linked_user is not None else None,
"login_email_synchronised": linked_user is not None,
},
)
else:
db.commit()
db.refresh(emp)
return emp