11# ruff: noqa: PLC0415
22from collections import defaultdict
3- from typing import List , Optional , Set , Tuple
3+ from typing import TYPE_CHECKING , List , Optional , Set , Tuple
44
55from django .contrib .auth import get_user_model
66from django .db import models
77from django .utils import timezone
88
9+ from src .accounts .enums import UserStatus
910from src .accounts .models import (
1011 AccountBaseMixin ,
1112 Notification ,
1819 FieldType ,
1920 PerformerType ,
2021 TaskStatus ,
22+ WorkflowEventType ,
2123)
2224from src .processes .models .mixins import (
2325 ApiNameMixin ,
3133 TasksQuerySet ,
3234)
3335
36+ if TYPE_CHECKING :
37+ from src .processes .models .workflows .raw_performer import RawPerformer
38+
3439UserModel = get_user_model ()
3540
3641
@@ -122,6 +127,7 @@ def _get_raw_performer(
122127 group_id : Optional [int ] = None ,
123128 user_id : Optional [int ] = None ,
124129 field = None , # Optional[TaskField]
130+ source_task_api_name : Optional [str ] = None ,
125131 ): # -> RawPerformer
126132
127133 """ Returns new a raw performer object with given data """
@@ -134,6 +140,7 @@ def _get_raw_performer(
134140 field = field ,
135141 api_name = api_name ,
136142 type = performer_type ,
143+ source_task_api_name = source_task_api_name ,
137144 )
138145 if user :
139146 result .user = user
@@ -151,12 +158,18 @@ def add_raw_performer(
151158 field = None ,
152159 api_name : Optional [str ] = None ,
153160 performer_type : PerformerType = PerformerType .USER ,
161+ source_task_api_name : Optional [str ] = None ,
154162 ): # -> RawPerformer
155163
156164 """ Creates and returns a raw performer for a task with given data
157165 Optionally updates the performers after create raw performers """
158166
159- if (
167+ if performer_type == PerformerType .MANAGER :
168+ if not source_task_api_name :
169+ raise Exception (
170+ 'Manager performer requires source_task_api_name' ,
171+ )
172+ elif (
160173 performer_type != PerformerType .WORKFLOW_STARTER
161174 and not group_id
162175 and not user
@@ -174,6 +187,7 @@ def add_raw_performer(
174187 group_id = group_id ,
175188 user_id = user_id ,
176189 field = field ,
190+ source_task_api_name = source_task_api_name ,
177191 )
178192 raw_performer .save ()
179193 return raw_performer
@@ -261,6 +275,7 @@ def update_raw_performers_from_task_template(
261275 'user_id' : e .user_id ,
262276 'group_id' : e .group_id ,
263277 'api_name' : e .api_name ,
278+ 'source_task_api_name' : e .source_task_api_name ,
264279 'field' : {
265280 'api_name' : e .field .api_name ,
266281 } if e .type == PerformerType .FIELD else None ,
@@ -309,6 +324,11 @@ def update_raw_performers_from_task_template(
309324 group_id = raw_performer_template .get ('group_id' ),
310325 field = field ,
311326 api_name = raw_performer_template ['api_name' ],
327+ source_task_api_name = (
328+ raw_performer_template .get (
329+ 'source_task_api_name' ,
330+ )
331+ ),
312332 ),
313333 )
314334 if new_raw_performers :
@@ -318,6 +338,38 @@ def update_raw_performers_from_task_template(
318338 api_name__in = deleted_raw_performer_api_names ,
319339 ).delete ()
320340
341+ def _resolve_manager (
342+ self ,
343+ raw_performer : 'RawPerformer' ,
344+ ) -> Optional [UserModel ]:
345+
346+ """ Resolve manager performer: find the user who completed
347+ the source step and return their manager.
348+ Returns None if source step not completed
349+ or completer has no manager. """
350+
351+ source_api_name = raw_performer .source_task_api_name
352+ if not source_api_name :
353+ return None
354+ from src .processes .models .workflows .event import WorkflowEvent
355+ complete_event = (
356+ WorkflowEvent .objects
357+ .filter (
358+ workflow_id = self .workflow_id ,
359+ task__api_name = source_api_name ,
360+ task__status = TaskStatus .COMPLETED ,
361+ type = WorkflowEventType .TASK_COMPLETE ,
362+ )
363+ .select_related ('user__manager' )
364+ .order_by ('-created' )
365+ .first ()
366+ )
367+ if complete_event and complete_event .user :
368+ manager = complete_event .user .manager
369+ if manager and manager .status == UserStatus .ACTIVE :
370+ return manager
371+ return None
372+
321373 def update_performers (
322374 self ,
323375 raw_performer = None ,
@@ -354,6 +406,7 @@ def update_performers(
354406 defaultdict (list ),
355407 defaultdict (list ),
356408 )
409+ raw_performers_for_update = []
357410 for raw_performer_ in raw_performers :
358411 if raw_performer_ .type == PerformerType .USER :
359412 user_ids [raw_performer_ .user_id ].append (raw_performer_ )
@@ -364,6 +417,13 @@ def update_performers(
364417 elif raw_performer_ .type == PerformerType .WORKFLOW_STARTER :
365418 user = self .get_default_performer ()
366419 user_ids [user .id ].append (raw_performer_ )
420+ elif raw_performer_ .type == PerformerType .MANAGER :
421+ manager_user = self ._resolve_manager (raw_performer_ )
422+ if manager_user :
423+ user_ids [manager_user .id ].append (raw_performer_ )
424+ elif raw_performer_ .task_performer_id is not None :
425+ raw_performer_ .task_performer_id = None
426+ raw_performers_for_update .append (raw_performer_ )
367427
368428 if api_names :
369429 user_fields = self .workflow .get_fields (
@@ -378,7 +438,6 @@ def update_performers(
378438 elif field .group_id :
379439 group_ids [field .group_id ].extend (api_names [field .api_name ])
380440
381- raw_performers_for_update = []
382441 created_performers_user_ids = []
383442 created_performers_group_ids = []
384443 if user_ids :
@@ -476,7 +535,9 @@ def _delete_orphaned_performers(self) -> Tuple[List[int], List[int]]:
476535 left pointing to the performer) """
477536
478537 task_performer_ids = list (
479- self .raw_performers .values_list ('task_performer_id' , flat = True ),
538+ self .raw_performers
539+ .exclude (task_performer_id = None )
540+ .values_list ('task_performer_id' , flat = True ),
480541 )
481542 performers_to_delete = (
482543 TaskPerformer .objects
@@ -501,6 +562,7 @@ def delete_raw_performer(
501562 group : Optional [UserGroup ] = None ,
502563 field = None ,
503564 performer_type : PerformerType = PerformerType .USER ,
565+ source_task_api_name : Optional [str ] = None ,
504566 ):
505567
506568 """ Delete a raw_performer
@@ -512,6 +574,7 @@ def delete_raw_performer(
512574 user = user ,
513575 group = group ,
514576 field = field ,
577+ source_task_api_name = source_task_api_name ,
515578 )
516579 if deleted_count :
517580 self ._delete_orphaned_performers ()
0 commit comments