diff --git a/app/modules/employees/service.py b/app/modules/employees/service.py index b9b9c34..92661d6 100644 --- a/app/modules/employees/service.py +++ b/app/modules/employees/service.py @@ -2555,6 +2555,33 @@ def _task_priority_label(task: ClientServiceTaskInstance) -> str: return dict(TASK_PRIORITIES).get(getattr(task, "priority", ""), getattr(task, "priority", "")) +def _employee_owned_task_condition(scope: EmployeeScope): + """Return the employee self-work ownership condition. + + Existing explicit task assignments remain authoritative. For legacy/open + engagements created before a staff assignee was propagated to task rows, an + unassigned Staff/Employee task is also treated as belonging to the + engagement's assigned staff member. Tasks explicitly assigned to another + user are never taken over by this fallback. + """ + role_name = func.lower(func.coalesce(ClientServiceTaskInstance.default_role_name, "")) + staff_role = or_( + role_name.contains("staff"), + role_name.contains("employee"), + ) + assigned_via_engagement = ( + ClientServiceTaskInstance.assigned_to_user_id.is_(None) + & staff_role + & ClientServiceTaskInstance.subscription.has( + ClientServiceSubscription.assigned_staff_user_id == scope.own_user_id + ) + ) + return or_( + ClientServiceTaskInstance.assigned_to_user_id == scope.own_user_id, + assigned_via_engagement, + ) + + def list_employee_work_dashboard( db: Session, scope: EmployeeScope, @@ -2587,7 +2614,7 @@ def list_employee_work_dashboard( ) .where( ClientServiceTaskInstance.tenant_id == scope.tenant_id, - ClientServiceTaskInstance.assigned_to_user_id == scope.own_user_id, + _employee_owned_task_condition(scope), ClientServiceTaskInstance.is_active.is_(True), ) ) @@ -2741,7 +2768,7 @@ def _employee_work_task_query(db: Session, scope: EmployeeScope, *, assigned_onl ) ) if assigned_only: - stmt = stmt.where(ClientServiceTaskInstance.assigned_to_user_id == scope.own_user_id) + stmt = stmt.where(_employee_owned_task_condition(scope)) if scope.branch_id is not None: stmt = stmt.where(ClientServiceTaskInstance.branch_id == scope.branch_id) if financial_year: @@ -3724,6 +3751,11 @@ def update_service_task_assignment( raise HTTPException(status_code=404, detail="Task not found") if getattr(task, "is_locked", False): raise HTTPException(status_code=400, detail="Locked task cannot be changed") + if task.assigned_to_user_id is None: + # Legacy engagement fallback: once the assigned staff member actually + # works the task, persist the normal explicit assignment. This never + # overwrites an existing/manual assignee. + task.assigned_to_user_id = scope.own_user_id if assigned_to_user_id: assignee = db.get(User, int(assigned_to_user_id)) @@ -3768,7 +3800,7 @@ def update_own_service_task_status( stmt = select(ClientServiceTaskInstance).where( ClientServiceTaskInstance.id == task_id, ClientServiceTaskInstance.tenant_id == scope.tenant_id, - ClientServiceTaskInstance.assigned_to_user_id == scope.own_user_id, + _employee_owned_task_condition(scope), ) if scope.branch_id is not None: stmt = stmt.where(ClientServiceTaskInstance.branch_id == scope.branch_id) @@ -3839,7 +3871,7 @@ def get_work_task_with_communications( if financial_year: stmt = stmt.where(ClientServiceTaskInstance.financial_year == financial_year.strip()) if assigned_only: - stmt = stmt.where(ClientServiceTaskInstance.assigned_to_user_id == scope.own_user_id) + stmt = stmt.where(_employee_owned_task_condition(scope)) task = db.execute(stmt).scalar_one_or_none() if not task: