Add consultant onboarding for firm administrators

This commit is contained in:
A R R R Associates
2026-07-17 13:55:14 +05:30
parent 46536bf96e
commit 9c04d97625
6 changed files with 141 additions and 15 deletions
+74 -11
View File
@@ -18,6 +18,7 @@ from app.modules.core.rbac.models import Role, UserRole
from app.modules.core.tenancy.models import Branch, FinancialYear, Tenant
from app.modules.clients.models import Client
from app.modules.employees.models import Employee
from app.modules.consultants.models import ConsultantProfile
from app.modules.services.models import (
FirmServiceSelection,
FirmServiceTaskTemplate,
@@ -268,6 +269,7 @@ ONBOARDING_ROLE_CONFIG: dict[str, dict[str, str]] = {
"default_designation": "Partner",
"default_department": "Management",
"default_employment_type": "full_time",
"requires_employee": True,
},
"manager": {
"role_name": "Branch Manager",
@@ -275,6 +277,7 @@ ONBOARDING_ROLE_CONFIG: dict[str, dict[str, str]] = {
"default_designation": "Branch Manager",
"default_department": "Operations",
"default_employment_type": "full_time",
"requires_employee": True,
},
"staff": {
"role_name": "Staff",
@@ -282,6 +285,15 @@ ONBOARDING_ROLE_CONFIG: dict[str, dict[str, str]] = {
"default_designation": "Staff",
"default_department": "Operations",
"default_employment_type": "full_time",
"requires_employee": True,
},
"consultant": {
"role_name": "Consultant",
"label": "Consultant",
"default_designation": "Consultant",
"default_department": "Consulting",
"default_employment_type": "consultant",
"requires_employee": False,
},
}
@@ -447,6 +459,13 @@ def create_firm_internal_user(
designation: str | None = None,
date_of_joining: str | None = None,
employment_type: str | None = None,
consultant_type: str | None = None,
firm_name: str | None = None,
specialisation: str | None = None,
gstin: str | None = None,
pan: str | None = None,
address: str | None = None,
remarks: str | None = None,
) -> dict[str, Any]:
actor_roles = set(get_user_role_names(db, actor.id))
if not actor_roles.intersection(FIRM_ADMIN_ROLES):
@@ -501,17 +520,60 @@ def create_firm_internal_user(
db.flush()
db.add(UserRole(user_id=user.id, role_id=role.id))
employee_link_result = _ensure_employee_for_onboarded_user(
db,
actor=actor,
user_obj=user,
employee_code=employee_code,
mobile=mobile,
department=(department or config.get("default_department") or ""),
designation=(designation or config.get("default_designation") or ""),
date_of_joining=date_of_joining,
employment_type=(employment_type or config.get("default_employment_type") or "full_time"),
)
consultant_profile = None
if role_key == "consultant":
duplicate_profile = db.execute(
select(ConsultantProfile).where(
ConsultantProfile.tenant_id == int(tenant_id),
ConsultantProfile.email == email_clean,
)
).scalar_one_or_none()
if duplicate_profile:
raise ValueError("A consultant profile with this email already exists in this firm.")
consultant_profile = ConsultantProfile(
tenant_id=int(tenant_id),
branch_id=int(branch.id),
user_id=int(user.id),
consultant_type=(consultant_type or "external_consultant").strip() or "external_consultant",
firm_name=(firm_name or "").strip() or None,
contact_person=name_clean,
email=email_clean,
mobile=(mobile or "").strip() or None,
specialisation=(specialisation or "").strip() or None,
gstin=(gstin or "").strip().upper() or None,
pan=(pan or "").strip().upper() or None,
address=(address or "").strip() or None,
status="active",
onboarding_status="invited",
is_platform_partner=False,
is_franchise_partner=False,
is_saas_customer=False,
is_active=True,
remarks=(remarks or "").strip() or None,
created_by_user_id=actor.id,
updated_by_user_id=actor.id,
)
db.add(consultant_profile)
db.flush()
employee_link_result = {
"required": False,
"created": False,
"linked_existing": False,
"employee_id": None,
}
else:
employee_link_result = _ensure_employee_for_onboarded_user(
db,
actor=actor,
user_obj=user,
employee_code=employee_code,
mobile=mobile,
department=(department or config.get("default_department") or ""),
designation=(designation or config.get("default_designation") or ""),
date_of_joining=date_of_joining,
employment_type=(employment_type or config.get("default_employment_type") or "full_time"),
)
try:
db.commit()
@@ -540,6 +602,7 @@ def create_firm_internal_user(
"role_label": config["label"],
"branch": branch,
"employee_link_result": employee_link_result,
"consultant_profile": consultant_profile,
"invite_url": invite_url,
"email_status": email_status,
"email_error": email_error,