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.models import Branch, Tenant
|
||||||
from app.modules.core.tenancy.settings_models import BranchSettings
|
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.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.documents.models import EngagementDocument
|
||||||
from app.modules.services.models import ClientServiceTaskInstance, ClientServiceSubscription, ServiceCatalogue, ServiceTaskComment
|
from app.modules.services.models import ClientServiceTaskInstance, ClientServiceSubscription, ServiceCatalogue, ServiceTaskComment
|
||||||
|
from app.modules.registrations.models import ClientRegistration, RegistrationType
|
||||||
from app.modules.services.execution import (
|
from app.modules.services.execution import (
|
||||||
CLOSED_TASK_STATUSES,
|
CLOSED_TASK_STATUSES,
|
||||||
TASK_PRIORITIES,
|
TASK_PRIORITIES,
|
||||||
@@ -2868,6 +2869,240 @@ def resume_employee_engagement_workflow(db: Session, scope: EmployeeScope, engag
|
|||||||
db.commit(); db.refresh(subscription); return subscription
|
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(
|
def list_employee_work_kanban(
|
||||||
db: Session,
|
db: Session,
|
||||||
scope: EmployeeScope,
|
scope: EmployeeScope,
|
||||||
@@ -2905,7 +3140,7 @@ def list_employee_work_kanban(
|
|||||||
ClientServiceTaskInstance.task_name.ilike(like),
|
ClientServiceTaskInstance.task_name.ilike(like),
|
||||||
ClientServiceTaskInstance.description.ilike(like),
|
ClientServiceTaskInstance.description.ilike(like),
|
||||||
ClientServiceTaskInstance.client.has(
|
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(
|
ClientServiceTaskInstance.catalogue.has(
|
||||||
or_(
|
or_(
|
||||||
@@ -2926,6 +3161,18 @@ def list_employee_work_kanban(
|
|||||||
)
|
)
|
||||||
).scalars().all()
|
).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 = [
|
columns = [
|
||||||
{"code": "pending", "label": "Pending", "cards": []},
|
{"code": "pending", "label": "Pending", "cards": []},
|
||||||
{"code": "in_progress", "label": "In Progress", "cards": []},
|
{"code": "in_progress", "label": "In Progress", "cards": []},
|
||||||
@@ -2945,12 +3192,29 @@ def list_employee_work_kanban(
|
|||||||
)
|
)
|
||||||
if engagement_id not in engagement_lookup:
|
if engagement_id not in engagement_lookup:
|
||||||
client = getattr(task, "client", None)
|
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_lookup[engagement_id] = {
|
||||||
"engagement_id": engagement_id,
|
"engagement_id": engagement_id,
|
||||||
"subscription": subscription,
|
"subscription": subscription,
|
||||||
"label": _subscription_label(subscription, task),
|
"label": _subscription_label(subscription, task),
|
||||||
"client_name": getattr(client, "client_name", None) or "Unlinked Client",
|
"client_name": scope_display["primary"],
|
||||||
"client_code": getattr(client, "client_code", None) or "",
|
"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": (
|
"service_name": (
|
||||||
getattr(getattr(subscription, "catalogue", None), "service_name", None)
|
getattr(getattr(subscription, "catalogue", None), "service_name", None)
|
||||||
or getattr(getattr(task, "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_(
|
or_(
|
||||||
ClientServiceTaskInstance.task_name.ilike(like),
|
ClientServiceTaskInstance.task_name.ilike(like),
|
||||||
ClientServiceTaskInstance.description.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))),
|
ClientServiceTaskInstance.catalogue.has(or_(ServiceCatalogue.service_name.ilike(like), ServiceCatalogue.service_code.ilike(like))),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -4029,7 +4293,7 @@ def list_engagement_progress_dashboard(
|
|||||||
or_(
|
or_(
|
||||||
ClientServiceTaskInstance.task_name.ilike(like),
|
ClientServiceTaskInstance.task_name.ilike(like),
|
||||||
ClientServiceTaskInstance.description.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))),
|
ClientServiceTaskInstance.catalogue.has(or_(ServiceCatalogue.service_name.ilike(like), ServiceCatalogue.service_code.ilike(like))),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user