
    i51j9                     2   d dl  d dlmZ d dlmZ d dlmZ d dlmZ d dl	m
Z
mZmZ d dlmZ dZej                   ej"                  ej$                  ej&                  ej(                  ej*                  ej,                  fZh d	Z G d
 dej2                        Zy)    )*fields)cmf_roadmapRoadmapExportDataManager)aliased)funcselect	nullslast)defaultdict   >   
ft_sourcesft_bql_sourcesui_view_form_optionsc                       e Zd ZdZej
                  j                  dgz   Zd Zd Z fdZ	 fdZ
dd fd	
Z fd
Zd fd	Ze edddd      d               Zed        Zed        Zed        Zed        Zed        Zed        Zed        Zed        Zed        Ze	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd       Zed        Zed fd	       Z xZS )
CmfRoadmapTncget_filtered_roadmap_by_levelc                 F    fd | j                   j                        S )Nc                     | sy | j                   dk(  r| S | j                  j                           | j                  j                        S )N
CmfProject)
class_nametree_parentloadvalue)childroot_parents    './modules/project/models/cmf_roadmap.pyr   z,CmfRoadmap._calc_parent.<locals>.root_parent    sE    </!!&&("5#4#4#:#:;;    )r   r   )selfr   s    @r   _calc_parentzCmfRoadmap._calc_parent   s!    	< 4++1122r   c                 X    | j                   j                  s| j                  sy d| _        y )Ngantt)
logic_type
is_changedis_newui_view_form)r    s    r   _calc_ui_view_formzCmfRoadmap._calc_ui_view_form+   s!    **;;#r   c                 *    t         |          ddgz   S )Nzmembers.responsibleztree_parent.activity)supersave_preload_fields)r    	__class__s    r   r+   zCmfRoadmap.save_preload_fields1   s    w*,0EG]/^^^r   c                    | j                   s| j                         | _         | j                   r| j                   j                  g d       | j                  sK| j                  r?| j                  j                  j                         r| j                  j                  | _        | j                  sK| j                   r?| j                   j                  j                         r| j                   j                  | _        | j                  s&t        j                  j                  dd      | _        | j                  r| j                   r-| j                   j                  s| j                  xs d | _        n| j                  r%| j                  j                  j                  d      sV| j                   r2| j                   j                  dk(  rd	| j                  xs d | _        nd
| j                  xs d | _        | j                  r9| j                   j"                  s| j$                  j"                  rt'        dd       t)        | T  |i |}| j                  r>t        j,                  j/                  |        t        j0                  j/                  |        | j                   j"                  r#t3        t        j4                  j6                         | j                   j"                  rj| j                   r^| j                   D ]O  }|j                   j                         | j                   k7  s+| j                   |_          |j*                  |ddi| Q |S )N)	cmf_ownercmf_owner_assistantsactivitylogic_prefixadd_object_typer   
productionT)codecache_inmemory1)Roadmapu   Дорожная картаzproject.baseu   Дорожная карта zRoadmap uL   Нельзя изменять memrers и tasks у корневого RoadmapabortnotifyF)parentr!   load_fieldsr0   r   r   modelsCmfActivitygetr&   r2   namer   
startswithr1   systemmembersr%   tasks	cmf_alertr*   saveCmfRoadmapQuickTransformscaffold_defaultsCmfRoadmapViewschedule_deferred_jobr   recalculate_cache)r    argskwargsresmemberr,   s        r   rF   zCmfRoadmap.save4   s\   {{++-DK;;KK##k $ 
 }}!1!1d6F6F6O6O6T6T6V ,,55DM}}1E1E1J1J1L KK00DM}}"..22UY2ZDM;;{{4;;#>#>#yy/C0	YYdiioo&@&@Ak&l;;4;;#;#;~#M">tyy?OC>P QDI"*499+;*< =DI ;;||&&$***?*?hptuglD+F+;;++==dC!!33D9<<""!&"3"3"E"EF ;;!!dkk,, ?==%%'4;;6$(KKFMFKK>e>v>? 
r   F)skip_owner_checkc                
   t         j                  j                  |       D ]  } |j                  |ddi|  t         j                  j                  |       D ]  } |j                  |ddi|  t        |   |d|i|S )N)r;   rP   T)r=   rG   listdeleterI   r*   )r    rP   rL   rM   qtviewr,   s         r   rS   zCmfRoadmap.deletef   s    1166d6C 	>BBIIt=d=f=	>))..d.; 	@DDKK???	@w~tQ6FQ&QQr   c                    t        |   |i |}t        j                  j	                  | d      D ]  } |j                  |i |  t        j
                  j	                  | d      D ]  } |j                  |i |  |S )NT)r;   include_deleted)r*   restorer=   rG   rR   rI   )r    rL   rM   rN   rT   rU   r,   s         r   rX   zCmfRoadmap.restorem   s    got.v.1166dTX6Y 	(BBJJ''	())..dD.Q 	*DDLL$)&)	*
r   c                    t         |   ||       t        j                  ry | j	                  g d       | j
                  sy |*| j                  d      D ch c]  }|j                   }}nt        |      }|t        z  sy t        j                  | j                         v ry t        j                  j                  d       y c c}w )N)manage_by_owner_onlyr.   r/   r;   T)r%   u   Не достаточно прав на управление Диаграммой Ганта. Обратитесь к администратору или владельцу проекта)message)r*   check_edit_permgdisable_permissionsr<   rZ   valuesr   setGENERATOR_FIELDScurrent_person
get_ownersr=   CmfAccessListcheck_admin_mode)r    changed_fields_to_checkadditional_error_msgfchangedr,   s        r   r\   zCmfRoadmap.check_edit_permu   s     79MN  `a(("*-1[[D[-IJq||JGJ12G**t00--u 	. 	
 Ks   C<      )	only_oncesoft_time_limit
system_jobpriorityc            	      V   t         j                  }d}d}|j                  ddg      D ]  }|dz  }t        |j                        }|j
                  |k7  r|dz  }t        j                  d|j
                   d| d|j                          ||_         |j                  d	
       |j                  j                  |j
                  j                  d}t        d|j                   |       t        d|       |dz  dk(  st                 t        j                  d| d| d       |S )u;   Актуализация кеша кол-ва членов.r   cache_members_countrC   r      zUpdate cache_members_count z ->  T)	only_data)node_idelements_countztree-node-count-changes-ztree-node-count-changes2   zRecalculate /z roadmaps caches)r=   r   rR   lenrC   rq   r]   debugidrF   r   cmf_emit_event
cmf_commit)_kwargsclstotal_count
calc_countr   
real_count
event_datas          r   rK   zCmfRoadmap.recalculate_cache   s-    
88,A9+M8N 	K1K[001J..*<a
5k6U6U5VVZ[eZffghshvhvgwxy2</   40)4)=)=Q\QpQpQvQvw
!9+..9IJJW!8:FB!#	  	
,zl!K=8HIJr   c                    g }g }| D ]Y  }|}|j                  |      }	|	r|n|}
|	rt        j                  nt        j                  }|}d }|	r|j	                  dd      d   }t        ||d       }|t        d| d|j                   d       t        |t              st        d| dd       t        |
|d       rt        |
|      }|j                  |      }nat        |d	d
      r5t        |t        j                        st        j                  ||
|||      }nt        |t        j                  t        j                   f      rt        |
|dz   d       }nt        |t        j                        r|j#                         }|j%                  |      }|j&                  }|j(                  rd}d}nd}d}t+        j,                  t+        j.                  |j0                  |         d       }t3        |g      j5                  |j0                  |   |
j6                  k(        j9                         j                  |      }|8|j;                  |       |j;                  |       \ ||fS )N.rr   u
   Поле "u   " не найдено в Tr8   u&   Группировка по полю "u#   " не поддерживаетсяcustom_table_nor   _idright_idleft_id)rA   r=   CmfGanttTaskCmfTasksplitgetattrrE   r   
issubclassALLOWED_GROUP_TYPESlabelr   
CmfM2MBaser   _ext_scalar_columnCmfRelationCmfGenericRelationm2m_model_clsdp_model	__table__rightr
   array_remove	array_aggcr   wherer{   	as_scalarappend)query_fieldsgantt_prefixsa_task_modelsa_gantt_modeldata_driverto_be_selected_colsfinal_fieldsfield
field_nameis_gantt_taskSaModelCmfModelaliascol	field_cls	m2m_modelsa_m2m_modeltblmy_id_field_namesub_id_field_nameaggs                        r   _select_group_fieldszCmfRoadmap._select_group_fields   s=    ! 0	0EJ!,,\:M(5n=G.;v**HECC+A.%6I Jzl2KHL_L_K`aimni)<=B:,Nqrz~ wt,gu-ii& 9&7;JyZ`ZkZkDl$77'9V[]bcC	F,>,>@Y@Y+Z[!'55=$?C	6+<+<= ) 7 7 9I#.#7#7	#BL&00C +5(,5)+4(,6)++DNN355AR;S,TVZ[C!3%=..suu5E/F'**/TU%IKe  #**3/##J/a0	0d #L00r   c                 z   |sxt        t              }t        t              |d<   |d   d   j                  | D ch c]  }|d   	 c}       | D cg c]  }|d   d|d   f c}|d<   |j	                  |       |S |d   }t        t              }| D ]^  }||   }t        |t              r3|r|D ]  }||   j	                  |        6|d   j	                  |       K||   j	                  |       ` t               }	|j                         D ]"  \  }}
t        j                  |
|dd |      |	|<   $ |	S c c}w c c}w )ut  Строит рекурсивные группы Roadmap без потери задач с пустыми M2M.

        Пустые M2M-значения сохраняются отдельным ключом, чтобы экспорт вывел
        их в группе «Не назначено», а не пропустил при обходе групп.
        maprr   r{   Nr   )
r   rR   r`   updater   
isinstancedictitemsr   _nested_grouping)r   r   final_items_groupsitems_by_levelitemr   groupedkeyelrN   	sub_itemss              r   r   zCmfRoadmap._nested_grouping   sQ    (.N$/$4N5!5!!$++E,JDT$Z,JKLQ RD$t*dDJ!? RN1%%n5!!q	d# 	*Du+C#t$! 1**401
 DM((.##D)	* f%mmo 	^NC!229fQRjJ\]CH	^ 
3 -K Rs   D3D8c                    | j                         j                  j                  }t        t        | j
                        j                  j                  }| j                  rd\  }}nd\  }}t        t        j                  |j                  j                        g      j                  |j                  ||j                  |   |j                  j                  k(              j                  |j                  |   |j                  k(        j                  |j                  j                   dk(        j#                         j%                  |      S )u   Ключ сортировки по m2m-полю: первое по алфавиту имя среди связанных сущностей)r   r   )r   r   F)r   r   r   r   r=   modelr   r   r
   minr   r@   select_fromjoinr{   r   cmf_deletedr   r   )r   sa_modelr   m2m_tblrel_tblr   r   s          r   _m2m_sort_columnzCmfRoadmap._m2m_sort_column  s     ))+44>>&)//2;;EE??2G//2G//012W\\'799=N3OSZS\S\S_S_3_`awyy!12hkkABwyy,,56UU5\		+r   c                    t        |dd      }|rt        |t        j                        ry| j                  j
                  j                  | |      }t        |t        j                  t        j                  f      }|r|dz   n|}t        |j                  |   g      j                  |j                  j                  |j                  k(        j                         j                  |      S )uW   Колонка из внешней таблицы для кастомных полей r   r   Nr   )r   r   r   r   dpr   ext_sa_modelr   r   r   r   r   r{   r   r   )		cmf_modelr   r   r   r   ext_noext_tblis_relcol_names	            r   r   zCmfRoadmap._ext_scalar_column  s     $5q9Iv/@/@A,,**77	6JI(:(:F<U<U'VW)/:%Z		(+,-wyy||x{{23UU5\	+r   c                 b   g }t        |      D ]c  \  }}|t        |      k  r||   j                         nd}	|j                  |      }
|
r|n| }|
rt        j
                  nt        j                  }|
r|j                  dd      d   n|}t        ||d       }t        |t              xr t        |t        j                        }|rt        j                  |||      }nRt        ||d       xs t        ||dz   d       }|t        j!                  |||||      }n|
r|j#                  |      }|!|	dk(  r|j%                         n|j'                         }|rt)        |      }|j+                  |       f |r8|j+                  | j,                  j%                                 |j.                  | }|S )Nascr   rr   r   )	enumeratery   lowerrA   r=   r   r   r   r   r   typer   r   CmfM2Mr   r   r   r   r   descr   r   r{   order_by)
task_modelgantt_task_modelquerysort_fieldssort_ordersr   order_by_clausesidxr   
sort_orderr   r   r   r   r   is_m2mr   clauses                     r   
_sort_rowszCmfRoadmap._sort_rows"  s   #K0 	,JC583{;K5KS)//1QVJ!,,\:M+8'jH/<++&..I3@S!,Q/eJ	:t<I	40YZ	6==5YF 11)XuMh
D9hWXz\aOacg=h;$77	8YXbdijC"))E*C;","5SWWY388:F"6*##F+1	,2 ##JMM$5$5$78"ENN$45Er   c           
         i }d}t        dt        dz         D ]k  }g }t        ||   j                               }|s nHg }t	               }|D ]>  }||   |   D ]1  \  }}|||f}||vs|j                  |       |j                  |       3 @ |dkD  r2||dz
     r|j                  ||dz
            |r|j                  |       |rx|dkD  rb|r`||dz
     D cg c]  ^}}| }}}g }||   j                         D ]#  \  }}|D ]  }||v s|j                  |        # % d|dd|gdd|gg}|j                  |       |r;|s|	r6| j                  |j                        j                  |      j                  |j                  j                  |            } |r)| j                  ||j                  |j                  k(        } |r7|j                  |t         j"                  ||       \  } }!| j                  |!      } |	rt$        j'                  ||| |	|
|      } | j)                         }"g }t	               }|"D ]C  }#|#d   }||   |   D ]1  \  }}|||f}||vs|j                  |       |j                  |       3 E |||<   |}n |rt        |dd      D ]  }$||$   s
t	        ||$dz
           }%g }&||$   D ]R  \  }'}(})||$dz
     j+                  |(g       D ]1  \  }*}+|(|*|+f}||%vs|%j                  |       |&j                  |       3 T |&sz||$dz
     |&z   ||$dz
  <   |	st-        t              },||$dz
     D ]  \  }}-}|,|   j                  |-|f        | j                  |j                        j                  |      j                  |j                  j                  t        |,                  }.|r)|.j                  ||j                  |j                  k(        }.t$        j'                  |||.|	|
|      }.|.j)                         D #-cg c]  }#|,|#d      D ]  \  }-}|#d   |-|f  c}}-}#||$dz
  <    ||fS c c}}w c c}}-}#w )	Nr   rr   ORparent_task_idINr{   	in_filterr   r   r   )range
MAX_LEVELSrR   keysr`   addr   r   r   r{   r   filterin_r   op_gantt_task_idcollect_filter_expr=   r   r   r   allr?   r   )/sessionTask	GanttTaskr   levels_dictadditional_levels_dictfiltersglobal_bql_listchild_task_filterr   r   show_sub_itemsneed_gantt_joinr   final_levels_dict	max_levellevelconds	level_idslevel_ids_with_parentseen_triplestask_idparent_taskroot_idtripletid_previous_level_idsadditonal_tasks_of_prev_leveladd_task_idadd_task_parent_idsadd_task_parent_idquery_nquery_filterfiltered_idsrowllevel_triplesadded_triplesr   	parent_id_rootgrand_parent_id
grand_rootparents_by_idr   resort_querys/                                                  r   _filter_levelszCmfRoadmap._filter_levelsC  s#   
 	1j1n- H	EE[/4467I %'!5L$ =,7,>w,G =(K%{G<F\1$((0-44V<	== qy519%LL!34$LL!23 19=NuWXy=Y)Z'##)Z&)Z461<RSX<Y<_<_<a &8%82E &.15GG = D D[ Q %&& ')41CDt%BC	'O _-e{!--0<<TBII$''++V_J`a"%ll9d6K6Ky||6[\G,7,J,J"'$nn!%%	 -K -)G\ &nn\:G(33D)Wk[fhtuG&{{}(*%"u' AC!!fG0;E0B70K A,W");!@!5(,,V4188@	AA (=e$IQH	V 9a, "(+ #$5a!e$< = "->q-A 9)CE7B1q57I7M7MiY[7\ 93"+_j!I!6)--f5)008	99 %+<QU+Cm+S!!a%( %0$5M<MaRSe<T Q8%g.55~w6OPQ $+==#9#E#Ed#K#R#RSWSZSZS^S^_cdq_rSs#tL&'3'8'8DDYDY]f]i]iDi'j#-#8#8y,Xcepr~#L $0#3#3#50 07DSV7L0 4NG Q9090%a!e,="H !)++g *[Z0s   Q Q
c                     | |k(  ry|h}t        |dd      D ]_  }t               }|D ]B  }||   j                  |g       D ](  \  }	}
|
|k7  r|	|	| k(  r   y|j                  |	       * D |s y| |v r y|}a y)u   
        Проверяет, есть ли task_id в цепочке предков от parent_task_id до корня в ветке root_id
        Используется для обнаружения цикла связей
        Tr   r   F)r   r`   r?   r   )r	  r   parent_levelr  r   to_checklvlnext_to_checkr  pidroots              r   _is_in_branchzCmfRoadmap._is_in_branch  s     n$"#q"- 	%CEM +!,S!1!5!5c2!> +ICw { g~#!%%c*++ !  -'$H	%  r   c           	      Z    t         j                  j                  }t        t              t        t
              }t                t        d       fdfdfd} fd}	t        dt        dz         D ]  }
|
dz
     D cg c]  } ||
dz
        r| }}|s(|D ]u  }|
|j                  dt              kD  r|d	   }|j                  d
d      }|dk(  r| j                  |j                  |j                        j                  |j                  dk(  |j                  |k(  |j                  j                  |            j!                         }|D cg c]	  \  }}||f }}}n| j                  |j                  |j                        j                  |j                  dk(  |j                  |k(  |j                  j                  |            j!                         }|D cg c]	  \  }}||f }}}|D ]  \  }} |	|
||      s ||
||        x |st        j                  |
dz
  i       j#                               |j                  |
dz
  t                     z  }|D cg c]  } ||
dz
        s| }}|s|j$                  j                  |      |j                  dk(  |j&                  dk(  g}|s|j)                  |j*                  dk(          | j                  |j,                  |j$                        j                  | j!                         }|D ]$  \  }} |	|
||      s||
   j/                  |       &  t0        j3                  ddj5                  d j7                         D              z           fS c c}w c c}}w c c}}w c c}w )u@  
        Раскрывает дерево по связям: для каждого уровня берёт задачи с предыдущего уровня,
        находит их связанные задачи через CmfRelationOption, добавляет на текущий уровень

        Параллельно ищет циклы: если связанная задача уже встречается в своей ветке выше то это цикл,
        помечаем как цикл и не раскрываем дальше
        c                       t        t              S N)r   r`    r   r   <lambda>z2CmfRoadmap._process_linked_items.<locals>.<lambda>  s    +c2B r   c           
          |   j                  | g       }j                  |i       }|D ch c]$  \  }}| |j                  |t                     vs#|& c}}S c c}}w )u   
            Возвращает set root_id веток, в которых задача есть на уровне lvl
            и при этом ещё не помечена циклом
            )r?   r`   )r	  r%  entriescycle_at_level_pr(  r   link_cycle_per_roots         r   _get_non_cycled_brancheszBCmfRoadmap._process_linked_items.<locals>._get_non_cycled_branches  s_    
 "#&**7B7G044S"=N)0cXRG>CUCUVZ\_\aCb4bDcccs   $AAc                 t    ||f}||    vr
|g|    |<   y||    |   vr|    |   j                  |       yy)uN   Кладет (parent, root) в levels_dict[level][task_id] без дублейNr   )r  r	  r   r  entryr   s        r   _add_levels_entryz;CmfRoadmap._process_linked_items.<locals>._add_levels_entry  sZ    #W-Ek%00/4gE"7+k%099E"7+2259 :r   c                 ^    |    }||v r|||   vr||   j                  |       yy|g||<   y)uQ   Кладет parent в additional_levels_dict[level][task_id] без дублейNr6  )r  r	  r   bucketr   s       r   _add_additional_entryz?CmfRoadmap._process_linked_items.<locals>._add_additional_entry  sF    +E2F& !87O**>: 9 $2"2wr   c                     d} || dz
        D ]Y  }t         j                  ||| dz
  |      }|r,
j                  |||f       	|    |   j                  |       nd} | |||       [ |S )u  
            Кладёт связь parent -> task в каждую незацикленную ветку родителя, циклы помечает в link_cycle_per_root
            Возвращает True, если хотя бы одна ветка без цикла
            Frr   T)r   r)  r   )r  r   r	  added_non_cycler  is_cycler8  r4  r   r3  link_cycless         r   _process_pairz7CmfRoadmap._process_linked_items.<locals>._process_pair  s    
 $O3NEAIN 
K%33G^UUVYX_almOOWng$FG'.w7;;GD&*O "%.'J
K #"r      rr   level_torelation_type_id	directionoutinFz8ncget_filtered_roadmap_by_level additional_levels_dict= , c              3   D   K   | ]  \  }}d | dt        |         ywr%  =Nry   .0r%  idss      r   	<genexpr>z3CmfRoadmap._process_linked_items.<locals>.<genexpr>O  s8       X_s{svx{Z]^a]bbcdghkdlcmXn  X_    )r=   CmfRelationOptionr   r   r   r`   r   r   r?   r   
in_link_idout_link_idr   r   rC  r   r   r   r   is_dummyr   cmf_archivedr{   r   r]   rz   r   r   )!r   r   r   show_linked_itemsshow_child_tasksinclude_archivedRelation_linked_children_idsr;  r@  r  r  prev_level_idsrelation_typert_idrD  resultsin_idout_idpairsr   r	  candidate_idsids_for_childrenchild_filterchild_resultschild_idr  r8  r4  r   r3  r?  s!     `                         @@@@@r   _process_linked_itemsz CmfRoadmap._process_linked_items  s    ++44!,T!2*3/e)*BC	d	:	3	# 	#& 1j1n- 7	FE  +5195+C; N  "!2 N=,,ZDD%&89)--k5A	$%mmH,?,?AUAUV]] ,,5 11U: ++//? ce	 
 CJJeV_JEJ%mmH,@,@(BUBUV]] ,,5 11U: ,,00@ ce	 
 CJJfe_JEJ/4 N+NG$UNGD-eWnMN+N2   .22519bAFFHIL`LdLdejmnenpspuLvv  4A#mCD\]`bgjkbkDlC#m #m#++//0@A((E1.$L
 ,$++D,=,=,FG$VGMM$''4;N;N$O$V$VXd$e$i$i$kM/< F+)(	8D07;;HEFk7	Fr 	
Jdii  X_  @V  @\  @\  @^  X_  O_  _  	`%{22q& K K $ns   N"N
1N"
6N(N(c	                 &   |r\|gt        dt        dz         D 	cg c]  }	t        |d|	        c}	z   }
 | j                  t	        |
d      D 	cg c]$  \  }	}|j
                  j                  d|	 d      & c}}	 j                  |      }t        dt        |
            D ]7  }	|j                  |
|	   |
|	   j                  |
|	dz
     j
                  k(        }9 |j                  |j
                  j                  |            }|r)|j                  ||j                  |j
                  k(        }|rt        j!                  ||||||      }|j#                         }n|D cg c]  }|fdt        dz
  z  z    }}t%        t&              }|D ]p  }|d   }t        dt        dz         D ]S  }||dz
     }|dk(  rd n||dz
     }|||f}|||   vr
|g||   |<   2|||   |   vs=||   |   j)                  |       U r |S c c}	w c c}}	w c c}w )	NrA  rr   T)r@   r%  r   r,  r   )r   r   r	   r   r   r{   r   r   ry   	outerjoinr   r   r   r   r   r   r   r   r   r   r   )r   r   r   first_level_idsr  r   r   rW  r   ialiasesar   rowsr	  r   r  r  level_indexr   r7  s                        r   _build_levels_dictzCmfRoadmap._build_levels_dictR  sE    fU1j[\nE]^Qqc7 ;^^G "GMM7@!7LMtq!!$$**s1#S\*Mk$  1c'l+ d
GAJ4M4MQXYZ]^Y^Q_QbQb4bcd LL_!=>E

9d.C.Cy||.ST"--dIukS^`lm99;D L[[WJJN!;;[D[ "$' 	DC!fG$Q
Q7 	DkAo.)4)9s;QR??S?'1+k"::9>K,W5+k":7"CC,W5<<UC	D	D I  _ N \s   H)H
$Hc                    C | xs g } |xs g }|xs g }|xs g }|xs g }|xs g }t         j                  d| d| d| d| d| d| d|        |r;t               } |D ],  }!|!d   }"|"| v rt        d	|" d
       | j	                  |"       . ||||||||	|
|||||||||||g}#t        |#      D ]H  \  }$}%|%s	t        j                  j                  j                  t        j                  d|%i      d   |#|$<   J | r=t        j                  j                  j                  t        j                  d| i      d   } |r=t        j                  j                  j                  t        j                  d|i      d   }|r=t        j                  j                  j                  t        j                  d|i      d   }| j                  g d       | j                  g d       | j                  g d       |s| j                  g d       t        j                  j                  }&t        j                  j                  }'t        j                  j                  j                  }(|(j                         })|duxr |duxr
 ||k  xr | }*d}+d},dC|&j                  g}-|r:t         j#                  |C|&|'|(      \  }.}|-|.z   }-t         j                  d|        t%        Cfd|D              xs t%        Cfd|D              }/ |)j&                  |- j)                  |&      }0|/r)|0j+                  |'|&j,                  |'j                  k(        }0| |#d   g}1|r|r|1j                  |       |(j/                  |1t        j                  |&|0      \  }0}2|0j1                  |2      }0|rt         j3                  |&|'|0||C      }0|*r|0j5                  ||      }0|0j7                         }+|+D 3cg c]  }3|3d   	 },}3t         j                  dt9        |,              i }4|s|s|,D 5cg c]  }5|5d|5f	 c}5|4d<   nt         j;                  |)|&|'|,|/|||C	      }6t         j                  ddj+                  d |6j=                         D              z          t?        t@              }7t               }8|rt         jC                  |)|&|6|||      \  }7}8t         jE                  |)|&|'|(|6|7|#||||||/C      \  }4}9t         j                  ddj+                  d |4j=                         D              z          |4sdg i}4|r$g }:g };|+D ]<  }3tA               }<t        d g|z         D ]  \  }$}=|3|$   |<|=<    |:j                  |<       > t         jG                  |:||;      }>|s|retI        d!9dz         D ]S  }?|4|?   D ]I  \  }5}@}A|;D ]>  }B@|Bd"   |?dz
     v sB|?   j                  |5@Af       |Bd"   |?   j	                  |5       @ K U |;D ]  }B|BjK                  d"        tA        |>      }4t         j                  d#dj+                  d$ |4j=                         D              z          |r8rtM        |8      |4d%<   t         j                  d&       |4S c c}3w c c}5w )'ui  
        1) Делаем большой запрос с 20 JOIN (T1..T20) и узнаём, какие задачи есть на каждом уровне.
        Сохраняем в levels_dict = {1: {id: [(parent_id, root_id), ...]}, 2: {...}, ...}.

        2) Для каждого уровня (1..20) делаем новый запрос, где:
        - Условие: CmfTask.id IN (levels_dict[level])
        - Плюс фильтр по уровню — если он задан
        - Плюс глобальный фильтр — если он задан

        3) Результат: словарь {1: [(id_1, parent_id_1, root_id_1), ...], 2: [...], ..., 20: [...]},
        где лежат уже отфильтрованные задачи на данном уровне.
        Если обнаружены циклы, возвращаем по ключу 'link_cycles' список узлов с задачами которые являются началом цикла

        4) Реализуем вложеную группировку, если переданы group_by_fields
        z4ncget_filtered_roadmap_by_level method_start: start=z, end=z, group_by_fields=z, show_linked_items=z, show_sub_items=z, sort_fields=z, sort_orders=rC  u+   Дублирование relation_type_id: Tr8   r   r   )r1   z!=ztask.gantt_project)r   ==F)rT  rs  F)rU  rs  FNzop_gantt_task.)r   r   r   r   z2ncget_filtered_roadmap_by_level group_by_fields : c              3   @   K   | ]  }|j                          y wr,  rA   rM  rh   r   s     r   rO  z=CmfRoadmap.ncget_filtered_roadmap_by_level.<locals>.<genexpr>  s     RQall<8R   c              3   @   K   | ]  }|j                          y wr,  ru  rv  s     r   rO  z=CmfRoadmap.ncget_filtered_roadmap_by_level.<locals>.<genexpr>  s'       ZKyzZ[ZfZfgsZt  ZKrw  r   z7ncget_filtered_roadmap_by_level : len(first_level_ids)=rr   z-ncget_filtered_roadmap_by_level levels_dict= rG  c              3   D   K   | ]  \  }}d | dt        |         ywrI  rK  rL  s      r   rO  z=CmfRoadmap.ncget_filtered_roadmap_by_level.<locals>.<genexpr>  s8       PLksknpsRUVYUZZ[\_`c\d[ePf  PLrP  z3ncget_filtered_roadmap_by_level final_levels_dict= c              3   D   K   | ]  \  }}d | dt        |         ywrI  rK  rM  r%  r   s      r   rO  z=CmfRoadmap.ncget_filtered_roadmap_by_level.<locals>.<genexpr>#  s8       RXoyortyTWX[W\\]^abg^h]iRj  RXrP  r{   rA  r   z*ncget_filtered_roadmap_by_level grouping: c              3   D   K   | ]  \  }}d | dt        |         yw)zgroup(z)=NrK  r{  s      r   rO  z=CmfRoadmap.ncget_filtered_roadmap_by_level.<locals>.<genexpr>D  s7       MWnxnqsxvVYUZZ\]`af]g\hMi  MWrP  r?  z*ncget_filtered_roadmap_by_level method_end)'r]   rz   r`   rE   r   r   r=   r   r   _get_filterr   r   r   r   Sessionr{   r   r   anyr   r   r   r   r   r   r   slicer   ry   rq  r   r   r   rg  r!  r   r   poprR   )Dinsert_bql_listr   lvl1_bql_listlvl2_bql_listlvl3_bql_listlvl4_bql_listlvl5_bql_listlvl6_bql_listlvl7_bql_listlvl8_bql_listlvl9_bql_listlvl10_bql_listlvl11_bql_listlvl12_bql_listlvl13_bql_listlvl14_bql_listlvl15_bql_listlvl16_bql_listlvl17_bql_listlvl18_bql_listlvl19_bql_listlvl20_bql_listrX  r   rW  rV  r   startendr   r   group_by_fieldsseenr   r]  r   rl  fltrr   r   r   r   to_be_slicedfirst_level_rowsrk  to_be_selected_fieldsadditional_fieldsr  first_queryr   first_query_filterr  r  r	  r   r   r?  r  
tasks_lvl1r   	task_datar   grouped_levels_dictr  r   r  final_items_groupr   sD                                                                      @r   r   z*CmfRoadmap.ncget_filtered_roadmap_by_level~  s   D */R)/R-3!'R!'R)/R	FugVTWSXXjkzj{ |%%6$77HHXXfgrfs  tB  CN  BOP 	Q 5D)  /0D= KE7S[_`	  =-=-NNNNNNNN	
 !) 	`GAt#^^..::6>>HVZK[\]^_
	` $nn//;;FNNXWfLghijkO$nn//;;FNNXWfLghijkO & 1 1 = =fnnxYjNk lmn o 	KL;<89""#@A ~~&&''00	nn''33%%'  $4$$ $#	 	  '!%	1;1P1Pl"9+ 2Q 2. %:<M$M!GGHHYZ[R/RR  KVY  ZK  J  ZK  WK#gmm%:;GGM%**9d6K6Ky||6[\K$gaj1	#4_-*5*H*H..	 +I +
'' "(();<$//ik[fhtuK%++E37K&??,-=>c3q6>>	I#oJ^I_`a $5L[#\WdG$<#\a $77y/k ,K
 GGCdii  PL  xC  xI  xI  xK  PL  GL  L  M%0%6"%K 6@6V6VT;0A$&673& ,6+D+Dy+{&!;	,(y 	
E		  RX  ~O  ~U  ~U  ~W  RX  IX  X  	Y !"B J!#' - F	 )4&?*B C .HAu'*1vIe$.!!),	- #-"="=j/[m"n  #4"1i!m4 ME<Me<T M81C M--1B51I%RS)1TT 1% 8 ? ?.Za@b c 1% 8 ? C CG LMMM &8 -!!%%e,- !%%8 9GG@499  MW  }N  }T  }T  }V  MW  DW  W  X /3K/@m,	<=  Q ? $]s   Y/Y4c                     t         S r,  r   )r   s    r   get_export_managerzCmfRoadmap.get_export_managerM  s    ''r   c                     |t        dd       |j                  dd       st        dd       |dk7  rt        dd       t        |   |d |||      S )	Nub   Невозможно экспортировать Roadmap без настроек фильтровTr8   r  zJExporting roadmaps without insert_bql_list is unavailable in this verison.xlsxz3Only xlsx file format is available in this verison.)field_namesbqlformat_filerX  filter_settings)rE   r?   r*   export2file)r   r  r  rX  r  r,   s        r   r  zCmfRoadmap.export2fileQ  st    "z  CG  H""#4d;bjno& KSWXw"{'+/:4D3B	 # D 	Dr   )NN) NNNNNNNNNNNNNNNNNNNNNNFNFNFNNNNN)Nr  FN)__name__
__module____qualname__	api_allowr   r   api_methodsr!   r(   r+   rF   rS   rX   r\   staticmethodcmf_deferred_jobrK   r   r   r   r   r   r!  r)  rg  rq  r   classmethodr  r  __classcell__)r,   s   @r   r   r      s   I((448Y7ZZK
3$_0d .3 R
( bTTUV W 4 61 61p " "H + + + +  @ w, w,r  6 v3 v3p ) )V 8<8< GK HL LP LP9>:>9>:>7<.2,048488<L! L!\ ( ( D Dr   r   N)cmf.includecmfr   modules.project.fieldsr   $modules.project.utils.roadmap_exportr   sqlalchemy.ormr	   
sqlalchemyr
   r   r   collectionsr   r   	CmfChoiceCmfChoiceIntCmfBoolCmfDater   r   r   r   ra   r   r-  r   r   <module>r     s      . I " . . #
 

NN
NN


  L GD'' GDr   