Show trade name in Staff My Work
This commit is contained in:
@@ -21,9 +21,10 @@ from app.modules.core.rbac.models import Role, UserRole
|
||||
from app.modules.core.tenancy.models import Branch, Tenant
|
||||
from app.modules.core.tenancy.settings_models import BranchSettings
|
||||
from app.modules.employees.models import Employee, EmployeeAttendance, EmployeeRegistrationRequest, EmployeeLeaveType, EmployeeLeaveBalance, EmployeeLeaveRequest, EmployeeDocumentType, EmployeeDocument, EmployeeOnboardingChecklistItem, EmployeeOnboardingTask, EmployeeOffboardingRequest, EmployeeOffboardingTask, EmployeeSalaryStructure, EmployeePayrollRun, EmployeePayslip
|
||||
from app.modules.clients.models import Client
|
||||
from app.modules.clients.models import Client, ClientBusinessUnit, ClientBranch
|
||||
from app.modules.documents.models import EngagementDocument
|
||||
from app.modules.services.models import ClientServiceTaskInstance, ClientServiceSubscription, ServiceCatalogue, ServiceTaskComment
|
||||
from app.modules.registrations.models import ClientRegistration, RegistrationType
|
||||
from app.modules.services.execution import (
|
||||
CLOSED_TASK_STATUSES,
|
||||
TASK_PRIORITIES,
|
||||
@@ -2868,6 +2869,240 @@ def resume_employee_engagement_workflow(db: Session, scope: EmployeeScope, engag
|
||||
db.commit(); db.refresh(subscription); return subscription
|
||||
|
||||
|
||||
|
||||
def _employee_work_scope_display_map(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_id: int,
|
||||
subscriptions: list[ClientServiceSubscription],
|
||||
) -> dict[int, dict[str, str]]:
|
||||
"""Resolve the display identity for Employee My Work without changing ownership.
|
||||
|
||||
Display priority:
|
||||
- registration scope: registration trade name -> business-unit trade/name ->
|
||||
branch name -> registration legal name -> client trade name -> client name
|
||||
- business-unit scope: business-unit trade/name -> client trade name -> client name
|
||||
- client-branch scope: branch name -> business-unit trade/name -> client trade/name
|
||||
- client scope: client trade name -> client name
|
||||
|
||||
The legal client remains available as context for scoped engagements.
|
||||
"""
|
||||
subscriptions = [row for row in subscriptions if row is not None]
|
||||
if not subscriptions:
|
||||
return {}
|
||||
|
||||
business_ids = {
|
||||
int(row.business_unit_id)
|
||||
for row in subscriptions
|
||||
if getattr(row, "business_unit_id", None)
|
||||
}
|
||||
branch_ids = {
|
||||
int(row.client_branch_id)
|
||||
for row in subscriptions
|
||||
if getattr(row, "client_branch_id", None)
|
||||
}
|
||||
registration_ids = {
|
||||
int(row.registration_id)
|
||||
for row in subscriptions
|
||||
if getattr(row, "registration_id", None)
|
||||
}
|
||||
|
||||
businesses: dict[int, ClientBusinessUnit] = {}
|
||||
if business_ids:
|
||||
businesses = {
|
||||
row.id: row
|
||||
for row in db.execute(
|
||||
select(ClientBusinessUnit).where(
|
||||
ClientBusinessUnit.tenant_id == tenant_id,
|
||||
ClientBusinessUnit.id.in_(business_ids),
|
||||
)
|
||||
).scalars().all()
|
||||
}
|
||||
|
||||
branches: dict[int, ClientBranch] = {}
|
||||
if branch_ids:
|
||||
branches = {
|
||||
row.id: row
|
||||
for row in db.execute(
|
||||
select(ClientBranch).where(
|
||||
ClientBranch.tenant_id == tenant_id,
|
||||
ClientBranch.id.in_(branch_ids),
|
||||
)
|
||||
).scalars().all()
|
||||
}
|
||||
|
||||
registrations: dict[int, ClientRegistration] = {}
|
||||
registration_types: dict[int, RegistrationType] = {}
|
||||
if registration_ids:
|
||||
for registration, registration_type in db.execute(
|
||||
select(ClientRegistration, RegistrationType)
|
||||
.join(
|
||||
RegistrationType,
|
||||
RegistrationType.id == ClientRegistration.registration_type_id,
|
||||
)
|
||||
.where(
|
||||
ClientRegistration.tenant_id == tenant_id,
|
||||
ClientRegistration.id.in_(registration_ids),
|
||||
)
|
||||
).all():
|
||||
registrations[registration.id] = registration
|
||||
registration_types[registration.id] = registration_type
|
||||
|
||||
# Registration scope can carry business/branch references even when the
|
||||
# engagement's denormalised scope columns are blank.
|
||||
extra_business_ids = {
|
||||
int(row.business_unit_id)
|
||||
for row in registrations.values()
|
||||
if row.business_unit_id and row.business_unit_id not in businesses
|
||||
}
|
||||
if extra_business_ids:
|
||||
businesses.update({
|
||||
row.id: row
|
||||
for row in db.execute(
|
||||
select(ClientBusinessUnit).where(
|
||||
ClientBusinessUnit.tenant_id == tenant_id,
|
||||
ClientBusinessUnit.id.in_(extra_business_ids),
|
||||
)
|
||||
).scalars().all()
|
||||
})
|
||||
|
||||
extra_branch_ids = {
|
||||
int(row.client_branch_id)
|
||||
for row in registrations.values()
|
||||
if row.client_branch_id and row.client_branch_id not in branches
|
||||
}
|
||||
if extra_branch_ids:
|
||||
branches.update({
|
||||
row.id: row
|
||||
for row in db.execute(
|
||||
select(ClientBranch).where(
|
||||
ClientBranch.tenant_id == tenant_id,
|
||||
ClientBranch.id.in_(extra_branch_ids),
|
||||
)
|
||||
).scalars().all()
|
||||
})
|
||||
|
||||
result: dict[int, dict[str, str]] = {}
|
||||
|
||||
for subscription in subscriptions:
|
||||
client = getattr(subscription, "client", None)
|
||||
client_name = (getattr(client, "client_name", None) or "").strip()
|
||||
client_trade_name = (getattr(client, "trade_name", None) or "").strip()
|
||||
client_code = (getattr(client, "client_code", None) or "").strip()
|
||||
|
||||
primary = client_trade_name or client_name or "Unlinked Client"
|
||||
secondary = ""
|
||||
context = ""
|
||||
scope_label = "Client"
|
||||
|
||||
scope_type = (getattr(subscription, "scope_type", None) or "client").strip().lower()
|
||||
|
||||
if scope_type == "registration":
|
||||
registration = registrations.get(getattr(subscription, "registration_id", None))
|
||||
registration_type = registration_types.get(getattr(subscription, "registration_id", None))
|
||||
|
||||
if registration:
|
||||
business = businesses.get(
|
||||
getattr(registration, "business_unit_id", None)
|
||||
or getattr(subscription, "business_unit_id", None)
|
||||
)
|
||||
branch = branches.get(
|
||||
getattr(registration, "client_branch_id", None)
|
||||
or getattr(subscription, "client_branch_id", None)
|
||||
)
|
||||
|
||||
business_trade_name = (
|
||||
(getattr(business, "trade_name", None) or "").strip()
|
||||
if business else ""
|
||||
)
|
||||
business_name = (
|
||||
(getattr(business, "business_name", None) or "").strip()
|
||||
if business else ""
|
||||
)
|
||||
branch_name = (
|
||||
(getattr(branch, "branch_name", None) or "").strip()
|
||||
if branch else ""
|
||||
)
|
||||
|
||||
primary = (
|
||||
(getattr(registration, "trade_name", None) or "").strip()
|
||||
or business_trade_name
|
||||
or business_name
|
||||
or branch_name
|
||||
or (getattr(registration, "legal_name", None) or "").strip()
|
||||
or client_trade_name
|
||||
or client_name
|
||||
or "Unlinked Client"
|
||||
)
|
||||
|
||||
registration_code = (
|
||||
(getattr(registration_type, "code", None) or "").strip()
|
||||
if registration_type else ""
|
||||
)
|
||||
registration_number = (
|
||||
getattr(registration, "registration_number", None) or ""
|
||||
).strip()
|
||||
|
||||
if registration_code and registration_number:
|
||||
secondary = f"{registration_code} · {registration_number}"
|
||||
else:
|
||||
secondary = registration_number or registration_code
|
||||
|
||||
if client_name and client_name != primary:
|
||||
context = f"Client: {client_name}"
|
||||
|
||||
scope_label = "Registration"
|
||||
|
||||
elif scope_type == "business_unit":
|
||||
business = businesses.get(getattr(subscription, "business_unit_id", None))
|
||||
if business:
|
||||
primary = (
|
||||
(getattr(business, "trade_name", None) or "").strip()
|
||||
or (getattr(business, "business_name", None) or "").strip()
|
||||
or primary
|
||||
)
|
||||
secondary = (getattr(business, "business_code", None) or "").strip()
|
||||
if client_name and client_name != primary:
|
||||
context = f"Client: {client_name}"
|
||||
scope_label = "Business Unit"
|
||||
|
||||
elif scope_type == "client_branch":
|
||||
branch = branches.get(getattr(subscription, "client_branch_id", None))
|
||||
business = businesses.get(
|
||||
getattr(branch, "business_unit_id", None)
|
||||
if branch else getattr(subscription, "business_unit_id", None)
|
||||
)
|
||||
if branch:
|
||||
primary = (getattr(branch, "branch_name", None) or "").strip() or primary
|
||||
secondary = (getattr(branch, "branch_code", None) or "").strip()
|
||||
|
||||
business_display = ""
|
||||
if business:
|
||||
business_display = (
|
||||
(getattr(business, "trade_name", None) or "").strip()
|
||||
or (getattr(business, "business_name", None) or "").strip()
|
||||
)
|
||||
|
||||
context_parts: list[str] = []
|
||||
if business_display and business_display != primary:
|
||||
context_parts.append(business_display)
|
||||
if client_name and client_name not in {primary, business_display}:
|
||||
context_parts.append(f"Client: {client_name}")
|
||||
context = " · ".join(context_parts)
|
||||
scope_label = "Client Branch"
|
||||
|
||||
result[int(subscription.id)] = {
|
||||
"primary": primary,
|
||||
"secondary": secondary,
|
||||
"context": context,
|
||||
"scope_label": scope_label,
|
||||
"client_code": client_code,
|
||||
"client_name": client_name,
|
||||
"client_trade_name": client_trade_name,
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
def list_employee_work_kanban(
|
||||
db: Session,
|
||||
scope: EmployeeScope,
|
||||
@@ -2905,7 +3140,7 @@ def list_employee_work_kanban(
|
||||
ClientServiceTaskInstance.task_name.ilike(like),
|
||||
ClientServiceTaskInstance.description.ilike(like),
|
||||
ClientServiceTaskInstance.client.has(
|
||||
or_(Client.client_name.ilike(like), Client.client_code.ilike(like))
|
||||
or_(Client.client_name.ilike(like), Client.trade_name.ilike(like), Client.client_code.ilike(like))
|
||||
),
|
||||
ClientServiceTaskInstance.catalogue.has(
|
||||
or_(
|
||||
@@ -2926,6 +3161,18 @@ def list_employee_work_kanban(
|
||||
)
|
||||
).scalars().all()
|
||||
|
||||
work_subscriptions: dict[int, ClientServiceSubscription] = {}
|
||||
for task in tasks:
|
||||
subscription = getattr(task, "subscription", None)
|
||||
if subscription is not None and getattr(subscription, "id", None):
|
||||
work_subscriptions[int(subscription.id)] = subscription
|
||||
|
||||
scope_display_map = _employee_work_scope_display_map(
|
||||
db,
|
||||
tenant_id=scope.tenant_id,
|
||||
subscriptions=list(work_subscriptions.values()),
|
||||
)
|
||||
|
||||
columns = [
|
||||
{"code": "pending", "label": "Pending", "cards": []},
|
||||
{"code": "in_progress", "label": "In Progress", "cards": []},
|
||||
@@ -2945,12 +3192,29 @@ def list_employee_work_kanban(
|
||||
)
|
||||
if engagement_id not in engagement_lookup:
|
||||
client = getattr(task, "client", None)
|
||||
scope_display = scope_display_map.get(
|
||||
int(engagement_id),
|
||||
{
|
||||
"primary": (
|
||||
(getattr(client, "trade_name", None) or "").strip()
|
||||
or getattr(client, "client_name", None)
|
||||
or "Unlinked Client"
|
||||
),
|
||||
"secondary": "",
|
||||
"context": "",
|
||||
"scope_label": "Client",
|
||||
"client_code": getattr(client, "client_code", None) or "",
|
||||
},
|
||||
)
|
||||
engagement_lookup[engagement_id] = {
|
||||
"engagement_id": engagement_id,
|
||||
"subscription": subscription,
|
||||
"label": _subscription_label(subscription, task),
|
||||
"client_name": getattr(client, "client_name", None) or "Unlinked Client",
|
||||
"client_code": getattr(client, "client_code", None) or "",
|
||||
"client_name": scope_display["primary"],
|
||||
"client_code": scope_display.get("client_code", "") or getattr(client, "client_code", None) or "",
|
||||
"scope_secondary": scope_display.get("secondary", ""),
|
||||
"scope_context": scope_display.get("context", ""),
|
||||
"scope_label": scope_display.get("scope_label", "Client"),
|
||||
"service_name": (
|
||||
getattr(getattr(subscription, "catalogue", None), "service_name", None)
|
||||
or getattr(getattr(task, "catalogue", None), "service_name", None)
|
||||
@@ -3635,7 +3899,7 @@ def list_visible_work_assignment_dashboard(
|
||||
or_(
|
||||
ClientServiceTaskInstance.task_name.ilike(like),
|
||||
ClientServiceTaskInstance.description.ilike(like),
|
||||
ClientServiceTaskInstance.client.has(or_(Client.client_name.ilike(like), Client.client_code.ilike(like))),
|
||||
ClientServiceTaskInstance.client.has(or_(Client.client_name.ilike(like), Client.trade_name.ilike(like), Client.client_code.ilike(like))),
|
||||
ClientServiceTaskInstance.catalogue.has(or_(ServiceCatalogue.service_name.ilike(like), ServiceCatalogue.service_code.ilike(like))),
|
||||
)
|
||||
)
|
||||
@@ -4029,7 +4293,7 @@ def list_engagement_progress_dashboard(
|
||||
or_(
|
||||
ClientServiceTaskInstance.task_name.ilike(like),
|
||||
ClientServiceTaskInstance.description.ilike(like),
|
||||
ClientServiceTaskInstance.client.has(or_(Client.client_name.ilike(like), Client.client_code.ilike(like))),
|
||||
ClientServiceTaskInstance.client.has(or_(Client.client_name.ilike(like), Client.trade_name.ilike(like), Client.client_code.ilike(like))),
|
||||
ClientServiceTaskInstance.catalogue.has(or_(ServiceCatalogue.service_name.ilike(like), ServiceCatalogue.service_code.ilike(like))),
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user