U
    hx                    @   s   d dl Z d dlZd dlmZ d dl mZ d dlmZ d dlZd dlZ	d dl
Z
d dlmZ d dlmZ d dlT d dlmZ d dlZd dlZd d	lmZ d d
lmZmZmZmZmZ G dd dejjjj ej!j"jj#Z#dS )    N)defaultdict)	timedelta)Decimal)FileStorage)relativedelta)*)CmfTUUID)CmfActiveEntity)ListDictMappingIterableTuplec                       s  e Zd Zejjjjjej	j
jjj ddddddddd	d
dddddddddddddg Zedd fdd
Zedd fdd
Zedd fdd
Zed d! Zd"d# Zd$d% Zd&d' Z fd(d)Zd*d+ Zd,d- Zd.d/ Zd0d1 Z fd2d3Z fd4d5Z fd6d7Zd8d9 Zd:d; Zd<d= Zd>d? Zd@dA Z dBdC Z!dDdE Z" fdFdGZ#dHdI Z$dJdK Z%dLdM Z&dNdO Z'dPdQ Z( fdRdSZ) fdTdUZ*dVdW Z+ fdXdYZ,dZd[ Z-d\d] Z.d^d_ Z/d`da Z0dgdbdcZ1dhdedfZ2didgdhZ3djdidjZ4dkdl Z5dkdmdnZ6dodp Z7dqdr Z8dsdt Z9dudv Z:dwdx Z;dydz Z< fd{d|Z= fd}d~Z>dd Z?dd Z@ fddZAdd ZBdd ZCdd ZDdd ZEdd ZFe fddZGeHIdeHjJZKedlddZLdd ZMdmddZNdd ZO fddZPdd ZQednddZRdoddZSdd ZTdd ZUdddddZVdd ZWdddddZXdd ZY fddZZ fddZ[dd Z\dd Z]dd Z^dd Z_dd Z`dd Zadd ZbddÄ Zcddń Zddp fddǄ	ZeddɄ Zfedq fdd˄	Zgedrdd̈́Zheds fddτ	ZiedtddфZjedu fddӄ	Zkedv fddՄ	Zledw fddׄ	ZmeneoddٍdxddۄZpendydd݄Zqdd߄ Zrdd Zsdd ZteneoddgddzddZud{ddZvedd Zwd|ddZxd}ddZyd~ddZzdd Z{dd Z|dd Z}dd Z~dd Zdd Zdd  Z fddZ fddZdddZeneoddؐdd	d
d Zendd ZendddZeneodؐddؐdddd Zdded fddZedddddd fdd
Ze fddZeeeddd Zed fd!d"	Zed#d$ Zddddddddddddddd%eeeeed& fd'd(Zd)d* Zeneoddgd+dؐd,d-d. Zd/d0 Ze fd1d2Zedd3d4Zd5d6 Z fd7d8Zd fd9d:	Zeddd;d<d=Z fd>d?Zd@dA ZdBdC ZdDdE ZeneoddؐdFdGdHdI Z fdJdKZed fdLdM	Zeded fdOdPZedeedQdRdSZeeedTdUdVZeeedTdWdXZdYdZ Zd[d\ Zeneoeeedd]d^d_Zdee ed` fdadbZdcdd Zdedf Z  ZS (  CmfTaskall_relation_personsapprove_onecopycopy_to_listcountcount_tasks_by_listscreate_dummy_taskcreate_task_from_templateclean_after_encryptdelete_dummy_taskgroup_changes_required_fieldsgroup_changes_list_recursivegroup_changes_statusesZgroup_changesZmark_clickedmovesave_dummy_taskZstatus_options_listtimetracker_change_timeui_getpublic_listZ
public_getcount_approversN)include_systemc                   s   |s| dd t j||S NsystemF)
setdefaultsuperlistclsr#   argskwargs	__class__ !./modules/task/models/cmf_task.pyr(   2   s    zCmfTask.listc                   s   |s| dd t j||S r$   )r&   r'   r   r)   r-   r/   r0   r   8   s    zCmfTask.countc                   s   |s| dd t j||S r$   )r&   r'   slistr)   r-   r/   r0   r1   >   s    zCmfTask.slistc                 O   s   t jf ddi|}|j|_d|_tjt|j |j	dd |j
rl|j
jd|ddsld |_d |_
|	  |  |  d|jiS )	NcodeZdummyT)Zskip_project_perms_checkPPP-TSK-CREATEF)objraise_errorid)modelsr   r6   r2   is_dummygZskipcache_select_for_updateaddstr_calc_projectprojectcheck_project_role_accessparentZ_calc_default_fieldsave)r*   r+   r,   Z
dummy_taskr/   r/   r0   r   E   s    zCmfTask.create_dummy_taskc                 C   s"  |  |  ddg  | js0td| j dd | jdd tjj| dddD ]}d |_	|
  qN| jD ]$}t| j| tjjrht| |g  qh| j
dd | jr| jj}d | _| j
dd |j| tjj| dd	D ]}|j| qtjjd
dd| gdd| ggddD ]}|j| q
tjj| dd}|D ]}|j| q2tjtjfD ](}|j| dd	D ]}	|	j|	 qdqRtjjdd| gddD ]}	|	j|	 qtjj| dD ]}
|
j|
 qtjj| dddD ]}|jdd qtjj| ddD ]}|jdd q| j|  d S )Nr8   
checklists   Не dummy task TabortTEXKOM_db_deleteparent_taskinclude_deletedr#   Z	only_datataskrI   ORout_link==in_linkfilterrI   )r?   rI   r4   =r?   )r?   rI   Zinclude_dummy)load_fieldssave_preload_fieldsr8   	cmf_alertr6   _delete_checklistsr7   r   r(   rH   r@   fields
issubclasscmfZ
CmfM2MBasesetattrop_gantt_taskvaluedpdeleteCmfShadowLinkCmfRelationOptionCmfTimeTrackerHistoryCmfListHistoryOTRCmfListHistoryRTECmfStatusHistoryCmfTaskResAssign
CmfCommentCmfAttachment)selfsubtask
field_namegtlinkreltt_history_listtthZmodelhrescomment
attachmentr/   r/   r0   r   b   s^    





zCmfTask.delete_dummy_taskc                 C   s  |  ddddddddd	d
g
 | jjr0| jj| _| jjrJ| jj| _d| j_| jjrj| j| jjk rj| jj| _| jjr|| jj| _| jjr| jjD ]}|| jkr| j| q| jj	r| jj
rtjjtjjd| jj	| jj
  }| j	r| j	|kr|| _	| jj
r| j
  d S )Nzcloned_from.parentzcloned_from.listszcloned_from.logic_typezcloned_from.priorityzcloned_from.deadlinezcloned_from.alarm_datezcloned_from.responsiblelistsprioritydeadlineTZtz)rU   cloned_fromr?   
logic_type
is_changedrw   responsiblerv   appendrx   
alarm_datedatetimenowtimezoneutcset_now)rj   lZdeadline_minr/   r/   r0   #_save_dummy_task_sync_from_template   s:    
     




"
z+CmfTask._save_dummy_task_sync_from_templatec                 C   s"  |    | js"td| j dd | D ].\}}t| | tjjrFq*|| |< d| | _	q*d| _| 
  d| _| j| jkrd | _ntd| j dd | jr|   | jr| jjrd| _g }|  D ]}|jr|| q| dd |D  |D ]}|jsd|_	q|   | j| j| j| jdS )	NrB   TrC   Fu)   Выставлен код у dummy-task: c                 S   s   g | ]
}|j qS r/   )
class_name.0fr/   r/   r0   
<listcomp>   s     z+CmfTask.save_dummy_task.<locals>.<listcomp>)r6   r2   name	parent_id)save_preparer8   rW   r6   items
isinstancer[   rY   Z
CmfBackrefr|   Z_load_changed_fieldsis_newr2   cloned_from_idr   rH   is_templatevaluesZcolumn_historyr~   rU   is_nullr@   r   r   )rj   changed_fieldskvZhistory_fieldsfieldr/   r/   r0   r      s@    zCmfTask.save_dummy_taskc                    s   | j std| j dd dt_|   |   |   |   | 	  | 
  |   |   |   |   |   |   |   |   |   |   |   |   |   |   | jjr|   ttjj| j ddddS )NrB   TrC   F)notifyemitaudit)!r8   rW   r6   r9   TEXCOM_ENABLE_GROWCACHE_HACKr<   _calc_parent_task!_calc_parent_task_has_child_tasks_calc_gantt_path_calc_gantt_task_calc_activity_calc_scheme_wf_calc_logic_type_calc_workflow_calc_status_calc_parent_logic_prefix_calc_ui_view_form_calc_fix_versionscalc_history_calc_wf_simple_logicZ_calc_perm_security_level_set_lists_from_parent_task_clean_result_textZ_clean_text_calc_checklistsr?   r|   _do_parent_is_changedr'   r[   r7   ZCmfModelr@   rj   r-   r/   r0   _dummy_save   s4    	
	zCmfTask._dummy_savec                 C   sD   d}| j dddgdd| jggdgdd	}|r@t|jd
d }|S )Nr2   z
SIMILAR TOz
%-[0-9]+\Zr=   rS   -cmf_created_atT)rR   order_byrI   -)sget
project_idintr2   split)rj   Z
max_numberlastr/   r/   r0    _get_current_code_number_from_db;  s    z(CmfTask._get_current_code_number_from_dbc                 C   s   t j}d}| jr| jj}d| j d| }| j d| d}|jj|dd}|  z2||rl||}n|  d }||| W 5 z|  W nF tj	j
k
r } z$td| d|j d	|j  W 5 d
}~X Y nX X | S )uN    Высчитывает следующий номер для кода
        Z	NOPROJECTznext_code_number-r   z.lock   )timeoutzlock release error z, lock_name z
, timeout N   )APPREDIS_DBr   r^   r   redislockacquirerelease
exceptionsZ	LockErrorr9   debugr   r   existsZincrr   set)rj   Zredis_dbsuffixkeyZlock_keyr   enext_code_numberr/   r/   r0   r   E  s$    
4zCmfTask.next_code_numberc              	   C   s   | j dkrd S t| jjtjs"d S |  \}}|s:|s:d S | jsd| jjrZt	| jj
 d || _d S | js||r|tjj | _|r| j|kr| j| j kr|| _| jjrt	| jj
 d| j d| jj
 d| d d S )NCLOSEDuF    обновлен с учетом плановых дат списка u'    не может быть дальше ())cache_status_typer   r?   r^   r7   
CmfProject_calc_list_plan_intervalr   r|   rW   captionr[   rY   CmfDateTimer   plan_end_daterj   list_plan_start_date_minlist_plan_end_date_minr/   r/   r0   _calc_alarm_date_listc  s,    

$zCmfTask._calc_alarm_date_listc                 C   s   | j s(| jjr| jr(| jjs(| jjs(d S | jjr4d S | ddg | jD ]6}|jsX|jrH|jrl| jsl|j| _|jrz|j| _	 qqH| js| jr| jj
jdkrt| j}|jr|j| _d S )Nzcomponents.default_responsiblezcomponents.default_ownerr   )r   r}   r|   responsible_idr?   
componentsrU   Zdefault_responsibleZdefault_owner	cmf_ownerr^   r   r   get_cache_projectr   )rj   compr=   r/   r/   r0   _calc_responsible  s8    
zCmfTask._calc_responsiblec                    s   | j sB| jjsB| jjsB| jjsB| jjsB| jjsB| jjsB| jjsBd S t	 
  | jjr| jr| jjjdkr| jrt| j}|jr| j| _| jr|   | jr| jjs| j r| j| j k rtjr| j  d S )Nr   )r   r   r|   statusrx   activityrv   plan_start_dater   r'   _calc_alarm_dater?   r^   r   r   r   r   Zauto_alarm_dater   r   r9   import_moder   rj   r=   r-   r/   r0   r     sR    

zCmfTask._calc_alarm_datec                    s$   | j r| jr| j  t j||S N)r   r   r   r   r'   _save_templaterj   r+   r,   r-   r/   r0   r     s    
zCmfTask._save_templatec                    s   | j jr| j rdS | js4| jjs4| jjs4| j js4dS | jjr| jrt| jdr| jjdrnt	
| jj | _ n| jj  r| jj | _ | jjrd}| jjD ] }|| jjkr|j jdgd}q|s| jr| jd j jdgd}|r|| _ | j st   dS )u   
        Вычисляем вид деятельности
        Метод вызывается из базового класса.
        :return:
        Nr   r   r   rY   r   )r   r|   r   r?   rv   hasattrr   r^   
startswithr   r   loadnewoldr'   r   )rj   Ztmp_activityr4   r-   r/   r0   r     s8    

zCmfTask._calc_activityc                 C   s   d S r   r/   r   r/   r/   r0   _calc_parent  s    zCmfTask._calc_parentc                 C   s   | j | j jkrd S | jrB| j s&d | _nt| jj| _| jdd | j	  t
jjdd| gddgd}|D ] }|j | j krj| j |_ |  qjd S )NTrJ   rH   rS   r?   r]   rR   rY   )r?   r   gantt_projectr   r   r   main_gantt_projectr@   r]   Ztask_parent_is_changed_hookr7   r   r(   )rj   child_tasksrL   r/   r/   r0   r     s    
zCmfTask._do_parent_is_changedc                 C   s  | j js$| jjs$| jjs$| jjs$d S | jr| jjr| j| jjkr| jddg | jjdkrd}| jj| _|   t	j
j| |d t| d S | jjrd S | j jr| j r|  }|r|| jkr|dddd	g || _|   d S | jjr| jrd }d }| d
dg | jjr4| jjjr4| jjj}| jjj}|r| jshd}|| _t	j
j| |d |   d S |rd}|| _t	j
j| |d |   d S d S )Nr?   logic_prefixtask.gantt_projectu   SimpleLogic: в задаче установлен проект равный проекту родительской задачиr?   textr   cmf_owner_assistantsr   r   z8responsible.primary_role.structural_project.default_listz1responsible.primary_role.structural_project_forceu   SimpleLogic: Задача добавлена в Структурный проект Главной роли исполнителяu   SimpleLogic: Проект сменен, т.к. в Главной роли исполнителя указано менять проект)tree_parentr|   r}   rH   r?   r   rU   r   r   r7   rh   add_comment_auditrW   Z_node_parentrV   primary_rolestructural_projectZstructural_project_force)rj   Z	sl_reasonr?   Zstruct_projectZstruct_project_forcer/   r/   r0   _HACK24052023_calc_parent  s`    


z!CmfTask._HACK24052023_calc_parentc                    s  | j js| jjs| jjsd S | jjr| j dkr| jr| jr| jjr| dg | j| jkr| jj| jkrtjj	| jddgd| _| js| j| _d S | j
jr| j jr| js| j jdkr| j dkr| jstjj	| jddgd| _| js| j| _| jrP| j dkrP| j jdkrP| jjdd | jrJtd | jD ]}| j|_|  q2d | _| j d	krbd | _| j jr| js| j jdkr| j dkr| jstjj	| jddgd| _| js| j| _ fd
d | jjr| j dkr| jr| jj  dkr| j| _n| jr | j| _d S )N	task.epictask.subprojectztree_parent.parentepicZtree_hidden)r?   sys_typerY   T)rI   u   Скрываем задачу в дереве проекта, её дочерние элементы вставляем вместо неёr   c                    s>   |  ddg | jdkr| S | jr8| jjdkr8 | jS | jS )Nztree_parent.logic_prefixr   r   )rU   r   r   r4   get_tree_parentr/   r0   r    s    

z2CmfTask._calc_tree_parent.<locals>.get_tree_parent)r   r|   r?   rH   r   r   rU   r7   Z	CmfFoldergetr{   r   r   Z
tree_nodesr   rW   r@   )rj   childr/   r  r0   _calc_tree_parentH  s    





	
zCmfTask._calc_tree_parentc                 C   s  | j rD| j}|rD|jjdkrD|ddg |jdkr<|| _qD|j}q| jjr| jr| jj  | jjjdkr| jjdkr| j| _nd | _| j	jr| jdkrt
ddd	 | j	| _| jjr| jdkrt
d
dd	 | j| _| jjr| jjdkr| jr| jj dkrd | _d S )Nr   r   r   r   r   ztask.subu2   У подзадач нельзя менять EpicTrC   u@   У подзадач нельзя менять Подпроект)r   r   r^   r   rU   r   rH   r|   r   r  rW   
subprojectr   )rj   Ztmp_tree_parentr/   r/   r0   r     s4    




zCmfTask._calc_parent_taskc                 C   s&   | j r
d S | jjsd S tj|  d S r   )r   r   r|   r7   CmfTimeTrackerZtimetracker_task_change_statusr   r/   r/   r0   _calc_timetracker  s
    zCmfTask._calc_timetrackerc                 C   s   | j s*| jjs*| jjs*| jjs*| jjs*d S |   d }|sF| jrF| j}|sf| jrft| jjt	j
rf| j}|s| jr| jj r| j}|s| jD ]}|j r|}q|s| jr| j}|| _d S r   )r   r   r|   r?   rH   	main_listZ_load_perm_fieldsr   r^   r7   ZCmfDocumentperm_has_aclr   rv   perm_parent)rj   r  r   r/   r/   r0   _calc_perm_parent  s4    	



zCmfTask._calc_perm_parentc                    sT   t   }dd | jD |d< dd | jD |d< | j|d< | j|d< | j|d< |S )	Nc                 S   s   g | ]}| d ddgqS r6   r   r2   Zto_jsonr   ir/   r/   r0   r     s     z1CmfTask.get_cache_fields_json.<locals>.<listcomp>rv   c                 S   s   g | ]}| d ddgqS r  r  r  r/   r/   r0   r     s     tags
is_checkedr   activity_id)r'   get_cache_fields_jsonrv   r  r  r   r  )rj   retr-   r/   r0   r    s    



zCmfTask.get_cache_fields_jsonc                 C   s|   d }d }| j D ]P}|jdkrq|jjr>|d ks8|j|k r>|j}|jjr|d ksX|j|k r|j}q|st|rttjj }||fS Nr   )	rv   r   r   is_not_nullr   r[   rY   r   r   )rj   r   r   Zw_listr/   r/   r0   r     s    

z CmfTask._calc_list_plan_intervalc                 C   sz  | j jr<t| j r|s<|s<| js&| jr,d | _d | _d | _d S d }| jrX| jrX| j| j }| j jrx|rx|| _|| _| j| _| jjr|r|| _| jjr|r|| _| jjr|s|r|d | _|r|r| jr| j|ks| j|k r| jjrt| jj d || _|r| j| | _n|r|| _|rP| jr8| j|krPt| jj d || _| jrv| jrv| j| jk rv| j| _d S )Nr   uP    установлена в соответствии с планом списка)	rv   r|   lenr   r   r   r   rW   r   )rj   r   r   Zself_plan_shiftr/   r/   r0   _calc_plan_list  sZ    

zCmfTask._calc_plan_listc                 C   s   | j jr| j r| jdkr| jr| j | jk sT| jr<| j | jksT| js| j | j jdkr| j | j }| j | _| jr~| j j|7  _td |   d S )NOPEN
   uM   План сдвинут в соответствии с будильником)	r   r|   r   r   r   daysr^   rW   
_calc_name)rj   Z	date_diffr/   r/   r0   _calc_plan_nolist?  s2    

		zCmfTask._calc_plan_nolistc                 C   sZ   | j js"| js"| jjs"| jjs"dS |  \}}t| j s@| j jrN| || n |   dS )u`   
        Ф-я вызывается из базового класса
        :return:
        N)	rv   r|   r   r   r   r   r  r  r!  r   r/   r/   r0   
_calc_planU  s    zCmfTask._calc_planc                 C   s8  | j s"| jjs"| jjs"| jjs"d S | jjr4| j s4d S | jrH| jjjdkrbd| _tjj	| dd d S | 
 }| js|jsd| _tjj	| d|j d d S | jr|jr| jr| jjrd| _tjj	| dd | j| jjks| jj| jjkrtj| jkrd| _tjj	| dd | j r4| jjr4| jr4| js4d| _d S )	Nr   Tu~   SimpleLogic: Задача согласована автоматически, т.к. это Непроектная задачаr   u   SimpleLogic: Задача согласована автоматически, т.к. согласование отключено в Fu   SimpleLogic: Выполнен сброс согласования, т.к. сменился Постановщик или Проектu   SimpleLogic: Задача согласована автоматически, т.к. постановщик - руководитель.)r   approvedr|   r   r?   r^   r   r7   rh   r   _get_sl_optionssl_task_need_approveZsl_controller_strr6   r9   current_personZ
cmf_import
is_defined)rj   
sl_optionsr/   r/   r0   _calc_approvedo  sN    
 
"zCmfTask._calc_approvedc                    s   t t  }| ddg | jD ]&}||j |jD ]}|| q8q"| jjrt | jj	t | jj
 D ]4}|ddg ||j |jD ]}|| qqj| jr| jjds| j D ]}|| qt|S )Nzlists.cmf_ownerzlists.cmf_owner_assistantsr   r   CmfProject:)r   r'   
get_ownersrU   rv   r:   r   r   r|   r   r   r?   r   r^   r   r(   )rj   r+   r,   Zownerslstownerr-   r/   r0   r,    s     


zCmfTask.get_ownersc                    sF   | j s | jjr| jr | jjs d S | jr*d S | jdkr8d S t   d S r  )r   waiting_forr|   r   r'   _calc_waiting_forr   r-   r/   r0   r0    s    
zCmfTask._calc_waiting_forc           	      C   s  | j js<| jjs<| jjs<| jjs<| jjs<| jjs<| jjs<dS tj	
drLdS |  }| j}d}| jr| jjdrd}t| jj}|r| js| jdkr|| _d| _| jjr| jr| jdkrd| _d| _| jdkr| jdkrd| _d| _|r.| jjr.| jr.|jr.|jr.tj| j kr.td	dd
 | jjsL| jjsL| jjr*| jr*| jjr| jj| jksx| jjs| j| _| jjr| jj| jkr| j| _| jjr| jr| jjr| jjj | jkr| j| jks| js| jj| _| jjr| jjs| jj| _| jjr*| js*d| _| jsT| jp<|| _| jdkrT| j| _| jr`dS d}| jjr| jjs| jjs| jjr| jjsd}| j jr| j jr| j jrd}| jjrd}| jjrd}|sdS | jdkrD| j jjdk}|s(| j j!ddds(| j j| j !dk}|rD| j jj"dkrL| jpH|| _| js| j|kr|sr|| _d| _|| _t#j$j%| d|j& dd | jjs| jjr| j|kr| jr| j| _t#j$j%| d| j dd | jdkr|sd| _d| _| jr@| j|kr@| jr@| jr@| j| _t#j$j%| d| j dd dS | j jj"dkr|j'r| j(r| j)j*rt+dd | j)D }nt#j,j-dd| gdddggd}|rtddd
 |j's| j(rt#j,j-dd| gdddggd}|rtd |j.r`| j/r`t#j,j-dd| j/gdddgd d| j0ggd}|s`| j/1d!g | j !d| j/_ | j/2  td" |j3r~| j4| j5kr~td# |r|j6rtj|  kr| j7s| j j!ddd$}|r|| _ | j8jr| j8j| _8td% q| j jj"dkrd| _| jdks
| jrd| _d| _dS | j jj"dkr| j7rL| j !d| _ td& q| js^| j9  | j jj"dkr| j| j: kr| j9  | j| _| j| _d| _t#j$j%| d'| jj& d(| j j& d)d dS | j j"d*kr| j jj"d*kr| js|j;rtd+dd
 td, | j jj"dkr:| jp&|| _t#j$j%| d-d | j jj"dkrt| j|krt| jp`|| _t#j$j%| d.d | js| j9  | j jj"d*kr| j| j: kr| j9  t#j$j%| d/| j j& d dS qؐqdS )0uS   
            Ф-я вызывается из базового класса
        NimportFr+  T	IN_REVIEWZapprove2Zapprove1_reviewu[   Только Владелец проекта может согласовать задачуrC   r  openZstatus_coder5   )r  IN_PROGRESSZapprove3_notassigneduh   SimpleLogic: Задачу переключили на Постановщика/Руководителя(u   ), т.к. не указан Будильник. Установите будильник, чтобы задача отобразилась у Исполнителяr   uM   SimpleLogic: Задачу переключили на Исполнителя(u   ), т.к. указан Будильник.Установите будильник, чтобы задача отобразилась у Исполнителяr   r   c                 S   s   g | ]}|j d kr|qS r   r   r   r4   r/   r/   r0   r   e  s     
 z1CmfTask._calc_wf_simple_logic.<locals>.<listcomp>rH   rS   r   !=rR   um   Для закрытия задачи необходимо закрыть все дочерние задачиu_   Вы закрыли задачу у которой есть Открытые подзадачиr6   zchild_tasks.cache_status_typeu}   Родительская задача закрыта автоматически т.к. закрыты все дочерниеu_   Внимание! В задаче остались незавершенные чек-листы)r5   u   Спасибо! Статус установлен в "Подтверждение закрытия", для проверки постановщиком или владельцем проектаu   Спасибо! Статус изменен на «Закрыто» т.к установлен флаг «Без подтверждения».uO   SimpleLogic: Задачу переключили на Постановщика(u   ), т.к. статус=''r5  uT   Нельзя брать в работу несогласованную задачу.um   Внимание! Вы взяли задачу без согласования с руководителем.u^   SimpleLogic: waiting_for  установлен т.к. статус снижен в in_progressui   SimpleLogic: waiting_for установлен т.к. статус перешел из open в in_progressu[   SimpleLogic: будильник установлен т.к. статус сменен на )<r   r|   r$  r}   r   r?   r   r/  osenvironr  r%  r   r^   r   r   r   r   approve_forapprove_for_placeZsl_only_owner_approver&  r9   r'  r,  rW   Zwaiting_for_idr   r   r   r   r2   workflowget_default_statusstatus_typer7   rh   r   r   Z,sl_deny_closing_task_before_closing_subtaskshas_child_tasksr   r(  r  r   r   t%   sl_сlose_task_after_closing_subtasksrH   r6   rU   r@   Z.sl_deny_closing_task_before_closing_checklistschecklists_items_countchecklists_items_done_countZsl_task_only_owner_close
no_controlstatus_closed_atr   r   Zsl_deny_no_approve)	rj   r)  Ztask_controllerZis_project_taskZ
need_transZsimple_logicZhas_unclosed_subtasksZ unclosed_subtasks_in_parent_taskZin_review_statusr/   r/   r0   r     s|    $2

	


 $







&

zCmfTask._calc_wf_simple_logicc                    s  t    | jjs4| jjs4| jjs4| js4| jjs4d S |  }| js~t	j
t	jkr~| jjr~| jt	j
kr~| jdksr|js~tddd | jjrd S |jd krd S |j}tj|d}tjtjj}| jjr| jr| jjdk r| jt	j
kr| jr| jj| jjkr| jj| | _d S | jjs(| jjrd| js<|| | _n$| jr`| j|| kr`|| | _n d S | js| jt	j
kr| jjr| jsd S | js|| | _d S )N   u   Нельзя сдвигать крайний срок блокирующей задачи, обратитесь к постановщикуTrC   )r   i  )r'   _calc_deadliner@  r|   r?   r   r   rx   r%  r9   r'  Zsystem_personr   rw   Z)sl_allow_executor_change_nofatal_deadlinerW   Zsl_deadline_shiftr   r   r   r   r   cmf_created_atager^   )rj   r)  Z
days_shiftshiftr   r-   r/   r0   rI    sj    





(zCmfTask._calc_deadlinec                 O   sR   |  ddg tjj|ddgd}|| jkr8| j| || jkrN| j| | S )Nrv   fix_versionsr6   
members.idr   )rU   r7   CmfListr  rv   removerM  )rj   Zsrc_list_idr+   r,   Zsrc_listr/   r/   r0   remove_from_list7  s    

zCmfTask.remove_from_listc                 O   s0   |  dg tjj|ddgd}| j| | S )Nrv   r6   rN  r   )rU   r7   rO  r  rv   r~   )rj   Zdst_list_idr+   r,   Zdst_listr/   r/   r0   r   A  s    zCmfTask.copy_to_listc                 C   s   t j|j| d | S )Nr  )r7   CmfActiveEntityFilterr  Zadd_active_entity)rj   	filter_idr/   r/   r0   apply_filterH  s    zCmfTask.apply_filterc                 C   s8   t jj|ddgd}|jr4| j|j | jdd | S )Nr   
filter_tagr   TrJ   )r7   rR  r  rU  r  rP  r@   )rj   rS  Zactive_entity_filterr/   r/   r0   remove_from_filterL  s
    zCmfTask.remove_from_filterc                 O   s>  |  dddg |s tddd |s0tddd t|}t|}|tjkrZ| | nH|tjkrp| | n2|tj	kr|| j
jjkrd | _
ntd| dd |tjkr| | n|tjkr| | nl|tj	kr(tj	j|d	gd
}| j
r | j
|kr td|j d| j
j ddd || _
ntd| dd | S )Nrv   rH   zparent_task.nameu   Укажите from_idTrC   u   Укажите to_idu(   Не могу перместить из r   r6   rY   u5   Нельзя переместить задачу в "u/   ", так как она находится в ""u&   Не могу перместить в )rU   rW   r   Zget_cls_by_tuuid_strr7   rO  rQ  rR  rV  r   rH   r6   r^   r   rT  r  r   )rj   Zfrom_idZto_idr+   r,   Zfrom_clsZto_clsZtarget_taskr/   r/   r0   r   U  s4    






 zCmfTask.moveFc                 K   s~   |d }|sdS |d dkr dS | d}tjjddd|gddd	| d
gggdgd}|rz|| jkrz|sz| j| dS dS Ntoken_sanitizedFr      #№@rM   r   ILIKEaliasz%"z"%r   T)lstripr7   ZCmfTagr  r  r~   )rj   	only_namectxrZ  tagr/   r/   r0   _process_tag_token  s$    
	zCmfTask._process_tag_tokenc                 K   sn   |d }|sdS |d dkr dS | d}tjjddd|gddd	| d
gggdgd}|rj|sj|| _dS dS rY  )r^  r7   ZCmfLogicTyper  r{   )rj   r_  r`  rZ  ltr/   r/   r0   _process_logic_type_token  s$    
	z!CmfTask._process_logic_type_tokenc                 K   s   |d }|sdS | dsdS |d}t|dk r8dS dddgd	d
dd| dgddd| dggg}tjj|d}|r|s|| _dS dS )NrZ  F)#   №@r[     
user_localrO   TrM   r   r\  %Zloginr:  )r   r^  r  r7   	CmfPersonr  r}   )rj   r_  r`  rZ  _filterpersonr/   r/   r0   _process_responsible_token  s$    

z"CmfTask._process_responsible_tokenc                 C   s0   |  }|  }|d| d| d| fkS )Nre  rf  rg  )lower)rj   stringZhashtagr/   r/   r0   hashtag_cmp  s    zCmfTask.hashtag_cmpc           	      K   s   |d }t j D ]4\}}| }|d| d| d| fkr qLqdS |s| jsj|| jj krjdS tjjtj	j
djdd	d	d	d	d
}||j }|d	k r|d7 }|t|
 d7 }|tddd }| jr|j| jjjkr| jjj|jkrdS || _|| _dS )NrZ  re  rf  rg  FTry   r   r   )ZdayZhourZminutesecondZmicrosecond   )monthsr   )rt  r   )cmfutilZ	RU_MONTHSr   ro  r   r   r   r   r   r   r   replacemonthr   r   r^   Zyearr   )	rj   r_  r`  rZ  Z	month_idxrw  r   rL  r   r/   r/   r0   _process_month_token  s>     
zCmfTask._process_month_tokenc                 C   s   |    dS )uG    Ф-я вызывается из базового класса
        N)_calc_from_namer   r/   r/   r0   r!  	  s    zCmfTask._calc_namec                    s  | j js$| jjs$| jjs$| jjs$d S | j jp.d}| }g }|D ]\}| d}t	 
 }|d= || | jf |rzq@| jf |rq@| jf |rq@|s@q@q@g }|r|| t|d }|| d||< | j jrj| j jrjd  fdd| j j D } fd	d| j  D }	t|t|	krj||	}
| d
g t| jD ]}|j |
krJ| j| qJ| jdkr| jr| jrt| jjs| j pd | _ n,| j r| j jdsd| j pd | _ n| j sd| _ d S )N z.,;:?!rj   r   .)rf  re  rg  c                    s"   h | ]}|  r|d d qS r   Nr   r   elZtag_symbolsr/   r0   	<setcomp><  s     
 z*CmfTask._calc_from_name.<locals>.<setcomp>c                    s"   h | ]}|  r|d d qS r|  r}  r~  r  r/   r0   r  =  s     
 	tags.namer   1ZEpiczEpic zEpic 1)r   r|   r   r  r}   r^   r   ro  striplocalsr   r~   rd  rb  rn  extendr  rstripr   
differencerU   r(   rP  r   r   r?   r   r   r   Zadd_object_typer   )rj   r   Zname_tokensZundefined_tokenstokenrZ  r`  Zdot_token_posZtags_old_nameZ	tags_nameZtags_for_deletera  r/   r  r0   ry    s`    



zCmfTask._calc_from_namec                 C   sX   | j js| jsd S | jdkr$d| _n0| jdkr6d| _n| jdkrHd| _n| j | _d S )N)r  gantt)r   ztask.gantt_subprojectr(   z
pfeed.basepost)r{   r|   r   r   ui_view_formui_namero  r   r/   r/   r0   r   U  s    


zCmfTask._calc_ui_view_formc                 C   s   |  ddddg | jsP| jrP| j dddg | jjdkrF| j| _n
| jj| _| js| jdkrt| j}|r| dg |j| _d S )	Nr   r   rH   r   zgantt_project.op_gantt_taskr]   r   z main_gantt_project.op_gantt_task)rU   r   rH   r   r   r   r   r   r   r/   r/   r0   _calc_gantt_projectg  s    

zCmfTask._calc_gantt_projectc              	   C   s   | j js| js| jjr@| j r*| j jds@| jdkr@tddd | jsJd S | jr^| jjjdkrx| j	stt
j| d | _	d S t   | j	st
j| d }|| _	W 5 Q R X d S )Nr+  r   r  r   u_   task.epic, task.subproject и task.gantt_project не могут быть без ПроектаTrC   r   )r   r|   r   r   r^   r   rW   r?   r   r]   r7   CmfGanttTaskZcreate_gantt_taskru  disable_acl)rj   r]   r/   r/   r0   r   w  s    

zCmfTask._calc_gantt_taskc                 K   st   | j jr(| j  | j| j j| j j | jjsD| jjsD|	ddrp| j
D ]$}|jrJ| j  | j   dS qJdS )u   
        Изменяем счетчики Оперативной Гант-задачи при изменении задачи
        Zlist_affect_gantt_taskFN)r   r|   r]   r   Ztask_status_is_changed_hookr   r   r   r   r  rv   Zaffect_gantt_taskZtask_plan_dates_is_changed_hook)rj   r,   r-  r/   r/   r0   _calc_op_gantt_task_counters  s    



z$CmfTask._calc_op_gantt_task_countersc                    s  | j rL| jj sL| jdkrL|  }|jrLtjdkrL| jj sL| jj sLt	ddd | j
sf| jr\d S t  S | jsv| j svd S t }| jddD ]6}|j|  kr|jds|jds||j qd	|ksd
|krl| jj s| jj rt| j
 }r|jd| dd | jj rD| j
jrD| j
j| j
jkrD| jsD| jjd| d d	|krX|d	 d
|krl|d
 t| j
}d|kr|jd| d | jr|jd| jj| d |d d|kr| j jr|jd| d |d d|kr|jd| d |d d|kr&|jd| d |d d|kr| jj rd| jdkrd| jjdkrd|jd| d n&| jjr|jd| d |jd| d |d d|kr|jd| d |d d|kr|jd| d |d d|kr| j!s| j!jr|jd| d |d d |krj|jd!| d | j"j#D ]2^}}}|d"kr,|jd#kr,|jd|| d q,|d  d$|kr|jd%| d |d$ |r|jd&| d d S )'Nr   Zsd_apiud   Редактирование запрещено, так как задача в статусе CLOSEDTrC   r|   Zcache_Z_idr?   r=   r3   )r4   Zuse_new_projectzPPP-TSK-MOVEr  r}   zPPP-TSK-ASSIGNzPPP-TSK-ASSIGNABLE)userr4   r   zPPP-TSK-MODIFY-OWNERrH   rv   r   zPPP-TSK-CLOSEzPPP-TSK-RESOLVEzPPP-TSK-TRANSITION
spectatorszPPP-VW-MANAGErx   zPPP-TSK-DEADLINEr   	executorszPPP-TSK-ASSIGN-EXECUTORSr~   rk  perm_security_levelzPPP-TSK-SET-SECURITYzPPP-TSK-EDIT)$r|   r   r   r%  Zsl_readonly_closed_taskr9   Z	api_scopeZmark_commentmarkrW   r   r8   r'   check_edit_permr   r   r   r   Zproject_perm_allow_fieldsr   endswithr:   r?   r=   r   r   r>   r   r   rP  r}   r^   r   r   r  _changes)rj   r)  Zchanged_fields_to_checkr   r=   Zchange_action
change_obj_r-   r/   r0   r    s    


$&













$











zCmfTask.check_edit_permc                    s^   |  ddddddg | js.| js.| jtjkrZ| jrPt| j}|j	d| d n
t
   d S )	Nr   r   r   rv   r}   r  zPPP-TSK-DELETEr  )rU   r   r   r   r9   current_userr   r   r   r>   r'   check_delete_permr   r-   r/   r0   r    s    
  zCmfTask.check_delete_permc                 C   sb   | j s^| jjr^| jjs^| jr^tjjdd| jgddddgdddgggdD ]}| j|_|	  qHdS )u  
        При создании задачи - у нее не указывается имя сразу, но уже создается нотифай с пустым именем.
        Но нотифай по str-полям когда пусто меняется на имя - не создается и не обновляет информацию в созданных нотифаях.
        Поэтому мы сделал этот ХАК с нарушением слоёв.
        obj_idrO   rM   r   rz  Nr:  )
r   r   r|   r   r7   	CmfNotifyr(   r6   r   r@   )rj   Ztask_notifyr/   r/   r0   _update_empty_task_notify&  s    
z!CmfTask._update_empty_task_notifyc                 C   s   | j rt| j jrd S d}| jjrRt| jjt| jj D ]}|j	dkr<|}q<q<|sZd S t| j}|D ]D}||krvqh|j	dkrqh|j
dkrqh|j
dkrtd | j| qhd S )NFlist.agile_sprintr   r5  u\   Внимание! Задача перемещена из Запущенного списка)r   r   r   Ztask_allow_multiple_sprintsrv   r|   r   r   r   r   r   rW   rP  )rj   Z
add_sprintappended_listZcurrent_sprintsZ
cur_sprintr/   r/   r0   _calc_sprints4  s*    




zCmfTask._calc_sprintsc              2      sJ  t | j}|dddddg7 }|ddg7 }|dg7 }|d	g7 }|d
g7 }|dg7 }|ddg7 }t| jdd}|dhkr|dddg S |dhkr|dddg S |r|ddhkr|ddddddddddddddddd d!g S |d"hkr|d#d$d%d&d'd(d)dd*ddd+d,d-ddddddddd d!g S |rl|dd.dhkrl|d/d0d1d2d3dd*d,d4d5dddddddddd d!d&d'd6d7g S |dhkr|d&d'd(d)d*d,ddddddddd d!g S |d*hkr|dd&d'd(d)d,ddddddddd d!g S dd8d9d:d;d<d=d>d?d&d'd@dAdBd$d-dCdDdEdFdGdHdIdJddKdLddMdNdOdPd4ddQdRdSdTdUdVd(d)ddd dd6d7ddg2}t  | S )WNlogic_type_idr   r  Zscheme_wf_idr8   cmf_modified_atcmf_modified_by_idr   rJ  Zperm_security_level_idzworkflow.save_eval_codeparent_logic_prefixzrequest_type.idTr  r   r   rC  r   r}   zparent_task.parent_idz.responsible.primary_role.structural_project_idz3responsible.primary_role.structural_project_list_idzstatus.textr/  r$  r?  r   r   r   r@  rF  r   rv   zmain_list.idzlists.logic_prefixzlists.cache_status_typezlists.plan_start_datezlists.plan_end_dater   r   rx   zcloned_from.idrw   zlists.affect_gantt_taskZ	status_idrG  Zstatus_review_atZstatus_in_progress_startZstatus_in_progress_endZstatus_modified_atop_gantt_task.actual_start_date
resolutionrD  rE  zparent.project_typezparent.auto_alarm_datezparent.logic_prefixz"parent.task_allow_multiple_sprintsrH   parent_task.logic_prefixzparent_task.is_templater   lists.ordernozlists.perm_has_aclzlists.sys_typezlists.default_task_logic_typer  zmain_list.plan_start_datezmain_list.plan_end_datezmain_list.ordernozmain_list.perm_has_aclmain_list.logic_prefixzactivity.prefixr>  Zcmf_modified_byr
  r  r   r]   z!scheme_wf.default_task_logic_typez$scheme_wf.default_subtask_logic_typezstatus.need_approver   r{   agile_story_points)r(   Zcache_cluster_fieldsr   keysr'   rV   )rj   required_fieldsr   rY   r-   r/   r0   rV   P  sv   






                                                           @zCmfTask.save_preload_fieldsc                 O   s:   t j| d d| _| jdd t jj| df|| d S )Nr   Zapprove4TrJ   Zapprove_started)r7   
CmfApproveZstart_approve_processr?  r@   CmfEventdo_eventr   r/   r/   r0   start_approve  s    zCmfTask.start_approvec                 C   s<   |  dddg | jjj| _g | _|   tj| d d S )Nzstatus.trans_approvedzstatus.trans_approved.status_toapprovers_forZapprove_success_full)	rU   r   Ztrans_approved	status_tor  r@   r7   r  r  r   r/   r/   r0   _approve_approved  s
    zCmfTask._approve_approvedc                 C   sN   |  dddg | jjr"| jjjn| j| _g | _| jdd tj| d d S )Nzstatus.trans_rejectedzstatus.trans_rejected.status_tor  T)approve_rejected_doneZapprove_rejected)	rU   r   Ztrans_rejectedr  r  r@   r7   r  r  r   r/   r/   r0   _approve_rejected  s
    zCmfTask._approve_rejectedc                 C   s&   |  dddg | jjj| _g | _d S )Nzstatus.trans_updatedzstatus.trans_updated.status_tor  )rU   r   Ztrans_updatedr  r  r   r/   r/   r0   _approve_updated  s    zCmfTask._approve_updatedc                 K   s   | d}| d}| d}g }|dkr4dddg}|dkrFdd	dg}t| |tjd
d}|rd||d< tjj f |}|r|jf d|i| | dg tj| jkr| j	tj | j
dd tj| d d S )Napprove_groupr  r   r$  Zapprover_levelrS   ZmasterZacceptedr9  rm  )r4   r  ZapproverZapprove_typerR   r  TrJ   Zapprove_success_one)r  dictr9   r  r7   r  Z_approve_onerU   r  rP  r@   r  r  )rj   r,   r  r  r   Zmaster_filterparamsZapprover/   r/   r0   r     s0    




zCmfTask.approve_onec                    s   dt _t j||S )NT)r9   r   r'   create)r*   r+   r,   r-   r/   r0   r  :  s    zCmfTask.createz$(?P<code>[A-Z\d]+(?:-[A-Z\d]+)*-\d+)c                 C   sP   |dkrd}| j |}dd|g}|r>|dddd |D gg}tjj|||dS )	u  
        Нужно в тексте найти все потенциальные коды. Можно просто все слова...
        Какие сложности:
            - код может быть практически любым max_len = 64
            - в имени ветки нельзя пробелы
        ОСВ: код вначале, и содержит ^([A-Z0-9]+-[0-9]+).*
        Nrz  r2   INr=   c                 S   s   g | ]
}|j qS r/   r6   )r   r=   r/   r/   r0   r   O  s     z.CmfTask.find_related_tasks.<locals>.<listcomp>rR   rY   r   )_TASK_CODE_SEARCH_REfindallr7   r   r(   )r*   r   rY   Zprojectsr   ZcodesZfilter_r/   r/   r0   find_related_tasks@  s    	
zCmfTask.find_related_tasksc                 C   s   | j s| jjs| jjsdS | j s(| jjrz| dg g }| jD ]}|jdkr>|| q>|D ]}| j| | j| q\| j s| jjrg }| jD ]}|jdkr|| q|D ]}| j| | j| qdS )u   
        При добавлении в список правильно выбирать поле lists или fix_versions
         в зависимости от типа списка
        Nzfix_versions.logic_prefixzlist.release)r   rM  r|   rv   rU   r   r~   rP  )rj   r   r4   r/   r/   r0   r   R  s0    



zCmfTask._calc_fix_versionsc                 C   s  |rzt  }| jr|| j | jr.|| j |s6d S dd |D }ttjjt |d dd ttjjdt |id d S | j	r| jj
r| js| jj
r| js| jj
s| jj
s| jj
sd S | jj
rttjjd t| jdd t }| jj
r| jjD ]^}}}|t|j q| jj
r@| jjD ]^}}}|t|j q"|sJd S ttjjt |d dd | jj
sx| jj
rttjjdt |id d S )Nc                 S   s   h | ]}t |jqS r/   )r;   r6   )r   r   r/   r/   r0   r  {  s     z2CmfTask._calc_lists_count_cache.<locals>.<setcomp>)list_idstask_idr,   r  )r(   rv   r  rM  schedule_deferred_jobr7   rO  Zrecalculate_count_cacherecalculate_cacher   r|   r   r;   r6   r   r  r:   )rj   from_deleterv   Zids_setr  r  r/   r/   r0   _calc_lists_count_cacheq  sV    

zCmfTask._calc_lists_count_cachec                 C   s`   | j jsd S t| j jt| j j D ]6}|jdkr4q$tjj	|
 r$td| ddd q$d S )Nr  u;   Задачу нельзя добавить в спринт u"   , попробуйте позже.TrC   )rv   r|   r   r   r   r   r   r   r   r   Zget_lock_keyrW   )rj   r  r/   r/   r0   _check_sprints  s    
zCmfTask._check_sprintsc              
      s
  |    | jr| js| jsdt_| jjr| jr| jjj	dkrt
| j}|jr| js| j|j d|jj d|j d}tjj| |d |jr|j| jkr| j|j d|jj d|j d}tjj| |d |   |   |   |   |   |   |   |   |   | jrN| jjrNt   | !  W 5 Q R X | "  | #  | $  | %  | &  | '  | (  t) j*|dd	i|}| +  tj,-|  |S | jr| . S | j/jr| j0jst1d
dd | j2js| jr| | j2krt1ddd | j2jrt| j2rtdddgddd| gdd| j2ggdd| j2gdd| gggg}tj3j4|drtt1ddd | jjr| 5  | 6  | 7  | 8  | 9  | :  | jjr| j;rt<| jj=t<| jj> D ]}|| j;krd | _;q| js| j;js| jjr| j;s| jD ]}|j?dkr|| _; q<q| jD ]}|j?dkrB|| _; qbqB| j;s| jD ]}|| _; qqp| jjr| j;r| @dg | j;j?dkrt<| jj>t<| jj= D ]}	|	j?dkr|	| _; qq| jjs| jr| jr| jjj	dkrt
| j}|jrd| jsd| j|j d|jj d|j d}tjj| |d | jjr| jj=r| j| jj=kr| jj=j	dkrt
| jj=}
|
j}|r|| jkr| jA| d|j d|
j d}tjj| |d |jr<|j| jkr<| j|j d|jj d|j d}tjj| |d | jjr| jj=r| j| jj=kr| jj=j	dkrt
| jj=}
|
j}|r|| jkr| jA| d|j d|
j d}tjj| |d | jjrvtjBsvt<| jj>t<| jj= D ]0}	|	jCdkrt1d|	j d| j ddd q| jsvt<| jj=t<| jj> D ]0}|jCdkrDt1d|j d| j ddd qD| D  |Eds| jjr| jFrtGt<d d!d"}|| jj>}|| jj=}|| }|| }tH||grtjIjJjK| jLjtG|tG|d#d$ | M  |   |   |   |   | N  | jOjrn| jOd%krn| j?d&krnt1d'| jO d(dd | P  | jQjrtjRjS| d)f|| | '  | (  | jTf | t) j*||}|jU|jLkrtVd*|W  d+tXjY d,tXjZ  | jCjrD| jCj>dkrD| j[rD| j\]  | j\D ]"}t   |^  W 5 Q R X q | j_f | | j`jrd| jab  | jcjrx| jad  | j2jr| jae  | jjs| j	r$| jjrt   | !  W 5 Q R X n^| jj	r$| jj=	r$| jj=j] 	r$|Ed-	s$| jf]  | jf	r$t   | g  W 5 Q R X | jj	r6| h  | jif | | j  d.D ]&}tk| |j	rNtltjmjn  	qv	qN| j2j	s| j	r| j2	r| j2j?] d/k	rtltjIjn | j2j	r| j2j=	r| j2j=j?] d/k	rtltjIjn | j?j
r | j?j=d/k
r d0| _o| jpj
r2| j
r2tq| jjtjr
r2| js| jp | t  | juj
sV| j
sV| j?j
rv| ju
rv| j?d1k
rvt1d2dd | +  | jvj
s| jwj
rtltjxjyd3tz| jLid$ tj,-|  |S )4NTr   uo   SimpleLogic: Задача добавлена в Список для Новых задач без Списка "   " проекта "rX  r   ut   SimpleLogic: Задача добавлена в Обязательный список для Новых задач "r   Fu   Пожалуйста, воспользуйтесь контекстным меню (троеточие) в панели инструментов задачиrC   uK   Нельзя добавлять задачу в eё же подзадачиrelation_type.coderO   system.additional_parentrM   rN   rP   r:  u   Задачи не могут быть родительской и дочерней, так как они связаны связью Дополнительный родитель/Дополнительная дочерняя задача.r  
list.boardr  	list.baseum   SimpleLogic: Задача удалена из Список для Новых задач без Списка "ut   SimpleLogic: Задача удалена из Обязательного списка для Новых задач "r   uS   Нельзя добавить задачу в Завершенный список "z" - "uU   Нельзя удалить задачу из Завершенного списка "from_sync_subtasks)rv   returnc                 S   sF   t  }| D ]6}|ddg |jdkr(q
|jdkr4q
||j q
|S )up  Фильтрует lists - оставляет только незакрытые спринты и возвращает множество ID этих спринтов

                Args:
                    lists (list): список lists

                Returns:
                    set: множество не закрытых спринтов
                r   r   r  r   )r   rU   r   r   r:   r6   )rv   Zsprints_idslist_r/   r/   r0   get_correct_sprints`	  s    	

z)CmfTask.save.<locals>.get_correct_sprints)r  sprints_to_add_idssprints_to_remove_idsr  )rL   r(   r  r  r   u   Вид отображения uk    временно не поддерживается, используйте "task", "list", "post", "gantt"Zspectators_changeduj   DEV: WARNING: У задачи после сохранения совпадает код и id task.values=z, request.url=z, request.data=r  )r   r?   r  r}   r   r$  r   r   r  us   DEV: Недопустимое перемещение простой задачи в структуру дереваr  ){r  r   r   r8   r9   r   r?   r|   r^   r   r   r   r   Zdefault_list_if_emptyrv   r~   r7   rh   r   default_listr   r   r   r   r   r   r   r   r   r   Zneed_approveru  r  r  r#  rI  r   r   r   r   r   r'   r@   r   CmfBackbonePeerobj_after_save_hookr   perm_encryptresult_textrW   rH   rb   r   ry  r  r   r  _calc_estimate_workr   r  r   r   r   r   rU   rP  r   r   r  r  rC  r(   anyr   _sync_subtask_sprintsZapplyr6   _calc_logic_type_change_guard_calc_agile_story_pointsr  _calc_structural_listr  r  r  Z_sdesk_before_super_saver2   printr   Zrequesturldatarx   Zstaff_control_blocked_personsr   Zcalc_staff_control_blockedr  r{   r]   Ztask_logic_type_is_changed_hookr   Z"task_gantt_project_is_changed_hook task_parent_task_is_changed_hookr  r  r   Z_sdesk_after_super_saver  getattrr  rR  r  cache_child_tasks_countr  r   r   Zhook_task_tags_changed_calc_hide_closed_task_notifiesr   r}   r  rg   sync_task_resourcesr;   )rj   r+   r,   r=   	audit_msginstrl  Zremoved_listr   r  project_oldZold_default_list_if_emptyZold_default_listr  Zsprints_newZsprints_oldsprints_to_addsprints_to_removeZself_instancerm  rl   r-   r/   r0   r@     s   









	44""



















,($0zCmfTask.savec                 C   s:   | j jr6| j dkr6ttjjt| jdtjt| j< d S )Nr   )	person_idr  )r   r|   r;   r9   r'  r6   "deferred_hide_closed_task_notifiesr   r/   r/   r0   r  	  s    
z'CmfTask._calc_hide_closed_task_notifiesc                 C   s   |ri t _d S t jsd S t j D ]X}dddgdd|d gg}tjj|ddid |d	d|d	 g tjj|ddid q"i t _d S )
Nr   r9  closedr  rO   rw   r   )rR   r   r  )r9   r  r   r7   r  Zbulk_updater~   )r*   ZrollbackZobj_datarl  r/   r/   r0   (apply_deferred_hide_closed_task_notifies	  s    z0CmfTask.apply_deferred_hide_closed_task_notifieschangedc                 C   s  | j js| jjs| jjr0| jjdkr0| jjdks| jjrP| jjdkrP| jjdks|dks|d k	s| js| jjrx| jj	js| jjr| jj
jsd S | dddddg | jj	jpd}| jjjpd}|| }| jj
j}| j j}d	}	|dk rd}g }
| jrft| jjD ]`}|jd
krq |j| jjd| j j| jj	j| jj
jd	| jd |j| jjd dd|||d q d S | jjrrt| jjD ]n}|jd
krq||| jjkr||j| jjd| j j| jj	j| jj
jd	| jd |j| jjd dd|||d q|t| jjD ]x}|jd
krq|| jjkr|
| |j| jjd| j j| jj	j| jj
jd	| jd |j| jjd dd|||d qt| jd}| j jr| j j|d< | jj	jr| jj	j|d< | jj
jr| jj
j|d< |r0| jD ]Z}|jd
ks||
krq|j| jjdf| d|kr|j| jjd dd|d d q|r| jD ]N}|jd
ks<||
krZq<|j| jj|jj||jj|jj||jjdd q<|r|dkr|j| jjd |||||	| jd |j| jjd d ||||d | jjdkrH| jjdkrH| jD ]L}|jd
ks||
krq|| jjd |j| jjd dd|||d q| jjdkr| jjdkr| jD ]V}|jd
ksj||
krqj|j| jjd||||	d  |j| jjd d!d|||d qjd S )"Nr   )startedr  rv   r  op_gantt_task.sched_durationop_gantt_task.sched_workop_gantt_task.actual_workr   r   r5  r~   )estimate_spestimate_durationestimate_workestimate_countrB  zscope-changed)timetracker_history_idtask_operatetask_list_operater  remaining_durationspent_durationrP  rB  r  r  r  Zchangez
rte-changer  )r  r   r  r  work-logged)r  r   r  r  r  Zhistory_dater  )r  r   r  r  r  r  rB  closer  zstate-change)r  r  r  Zunclose)r  r  r  r  Zreopened)r  r|   rv   r   r   r   r   r]   r(  Zsched_duration
sched_workrU   r^   actual_workr   Zhistory_otr_addr6   Zhistory_rte_addr~   r  
time_spentremaining_estimateZend_date)rj   r   	task_listtimetracker_historyr  r  r  r  r  r  Zappendedr-  r  r/   r/   r0   r   
  sN   



	

  
  

  

  






 


zCmfTask.calc_historyc                 C   s   | j j  | j j| _| jr(| jj   ddg}| | | jsDd S | j j| j_tjj	dd| g|d}|D ] }|j | j krj| j |_ |
  qjd S )Nr?   r]   rH   rS   r   )r?   r   r   r   rH   rU   r]   r7   r   r(   r@   )rj   rY   r   rL   r/   r/   r0    _change_parent_and_gantt_project
  s    

z(CmfTask._change_parent_and_gantt_projectc                 C   s   ddd| gdd| gg}t jj|ddD ]}|  q&t jj| ddD ]}|  qDt jjddd| gd	d| ggddD ]}|  qtd S )
NrM   rL   rO   r   TrQ   rK   rN   rP   )r7   r  r(   restorera   rb   )rj   rl  
gantt_taskrn   ro   r/   r/   r0   _restore_relations
  s    

&zCmfTask._restore_relationsrE   c          
      O   s  |rhd | _ | jdd tjj| |dD ]}|j|d|i| q&tjj| |dD ]}d |_|jdd qPddd| gd	d| gg}tjj||d
D ]}|j||dd| qtj	j| |dD ]}|j|d|i| qtj
jddd| gdd| gg|d
D ]}	|	j|d|i| qd S )NTrJ   rK   rF   )r   rI   rM   rL   rO   r   rQ   )rF   Zfrom_task_deleterN   rP   )r]   r@   r7   CmfTaskCodeHistoryr(   r`   r   r   r  ra   rb   )
rj   rF   r+   r,   r2   rL   rl  r  rn   ro   r/   r/   r0   _delete_relations
  s    &zCmfTask._delete_relationsc                 O   s&   | j s
d S | j D ]}|j|| qd S r   )rA   r`   )rj   r+   r,   	checklistr/   r/   r0   rX   
  s    
zCmfTask._delete_checklistsc                O   s   t jj| |dgdD ]}|j|d|i| qt jj| |dgdD ]}|j|d|i| qBt jj| |dD ]}|j|d|i| qld S )Nr   )rL   rI   r   rF   )r4   rI   )r7   rd   r(   r`   re   rf   )rj   rF   r+   r,   rr   r/   r/   r0   _delete_history
  s    zCmfTask._delete_historyc                 O   sr   t jj| ddgdD ]}|j|| qt jj| ddgdD ]}|j|| q:t jj| ddD ]}|j|| q\d S )NTrJ  )rL   cmf_deletedr   )r4   r  )r7   rd   r(   r  re   rf   )rj   r+   r,   rr   r/   r/   r0   _restore_history
  s    zCmfTask._restore_historyc                    s   |  ddddddddd	d
dg | jr>| jD ]}|j|| q,| j|| | j|| | j|| | j|| | j|| | j|| t	 j||}| j
dd |   | jr| jj dkrttjj | jr| j|  tj|  |S )Nr   r=   r   sdesk_sla_cyclesr   rH   rv   rM  r}   r  rA   T)r  r   )rU   r  r`   _delete_task_resourcesr  _delete_timetracker_history_delete_subtasksr  rX   r'   r  #_update_additional_parent_relationsrH   r   r   r  r7   r   r  child_task_deleter  Zobj_after_delete_hook)rj   r+   r,   Zsdesk_sla_cyclers   r-   r/   r0   r`   
  s4         
zCmfTask.deletec                    s@  t  j||}| ddddg |   |ddsD|   |   |   |   |dd }|ddr| |d< | j	dkr| j
f | n| jf | |r|jsd	|_|jd	d
 n| ddg | jr| j|   d	| j_| j  | j| jj | jjd	d
 n.| |   |   | | j | jd	d
 |S )Nr]   rH   zproject.default_gantt_task_typer   	recursiveFr?   r   TrJ   parent_task.has_child_taskszparent_task.parent_task)r'   r  rU   r  r  _restore_timetracker_history_restore_task_resourcesr  r  r   _restore_epics_subtasks_restore_subtasksrC  r@   rH   rV   _calc_cache_branch_gantt_path_recalc_gantt_path)rj   r+   r,   rs   r?   r-   r/   r0   r     s<    

zCmfTask.restorec                 O   s>   | dd}d|d< tjj| |d}|D ]}|j|| q(d S )NrF   Fr  r   rI   )r  r7   rc   r(   r`   )rj   r+   r,   rF   rp   rq   r/   r/   r0   r  7  s
    z#CmfTask._delete_timetracker_historyc                 C   s&   t jj| dd}|D ]}|  qd S )NTr$  )r7   rc   r(   r  )rj   rp   rq   r/   r/   r0   r  ?  s    z$CmfTask._restore_timetracker_historyc                 O   sX   | dd}tjj| |d}|D ]"}tjj|j|dr |j|| q tjj| dd d S )NrF   Fr  rI   )r6   rI   !   Подзадачи удаленыr   )	r  r7   r   r(   r   r6   r`   rh   r   rj   r+   r,   rF   
tasks_listrL   r/   r/   r0   _delete_epics_subtasksD  s    zCmfTask._delete_epics_subtasksc                 O   s:   t jj| dd}|D ]}|j|| qt jj| dd d S )NTr%  -   Подзадачи восстановленыr   r7   r   r(   r  rh   r   rj   r+   r,   r(  rL   r/   r/   r0   r   P  s    zCmfTask._restore_epics_subtasksc                 O   sH   | dd}tjj| ||d}|D ]}|j|| q"tjj| dd d S )NrF   FrG   r&  r   )r  r7   r   r(   r`   rh   r   r'  r/   r/   r0   r  Y  s    zCmfTask._delete_subtasksc                 O   s:   t jj| dd}|D ]}|j|| qt jj| dd d S )NT)rH   rI   r*  r   r+  r,  r/   r/   r0   r!  c  s    zCmfTask._restore_subtasksc                 O   s<   | dd}tjjdd| g|d}|D ]}|j|| q&d S )NrF   Fr?   rO   rQ   )r  r7   rg   r(   r`   )rj   r+   r,   rF   assignments
assignmentr/   r/   r0   r  l  s    zCmfTask._delete_task_resourcesc                 O   s0   t jjdd| gdd}|D ]}|j|| qd S )Nr?   rO   TrQ   )r7   rg   r(   r  )rj   r+   r,   r-  r.  r/   r/   r0   r  r  s    zCmfTask._restore_task_resourcesc                 C   s@   t jjdddgdd| ggdgd}|D ]}|jj}|  q&d S )Nr  rO   r  rN   zin_link.op_gantt_taskr   )r7   rb   r(   rP   r]   Z*additional_children_relations_changed_hook)rj   Z!additional_parent_tasks_relationsrelationZadditional_parent_gantt_taskr/   r/   r0   r  w  s    z+CmfTask._update_additional_parent_relationsc                    s   |  dddg |jdkr:|js:tjs:| j  tjj| _	| j
sX| jsX|jsX| jdd | jdkr|r|jdkr|js|jstjj| |d tj| t j|d	|i|S )
Nr?   r  Zcmf_author_idr   TrJ   project.servicedesk)rt   rt   )rU   	log_levelr8   r9   r   r  r   r  r6   r  r   Zis_recursion_saver@   r  privater7   ZCmfSDeskSlaTriggerZtask_changed_hookr  r  r'   _comment_save_hook)rj   rt   r+   r,   r-   r/   r0   r3  ~  s    

zCmfTask._comment_save_hookc                 O   sx   t jjdd| jgdddggd}|D ]}|  q$t jjdd| jfdd	 |D gdddggd}|D ]}|  qfd S )
Nr   rO   r  r9  Tr:  r  c                 S   s   g | ]
}|j qS r/   r  )r   cr/   r/   r0   r     s     z/CmfTask.clean_after_encrypt.<locals>.<listcomp>)r7   rh   r(   r6   r`   ri   )rj   r+   r,   Zcommentsrt   Zattachmentsru   r/   r/   r0   r     s     
0zCmfTask.clean_after_encryptc           	         s   |sg }|sdg}|sg }|dddgddddd	ggd
dddgddd ggg}|oV| d}|rn|rn|dd|gg}|d |d t j|f||||d|S )Nr   r   r9  r   r   r  r  r  r  rM   r  ZtrashrO   r   rS   r?   object_fieldsrR   rY   r   )r  r~   r'   field_options_list)	r*   relation_field_namer6  rR   rY   r   Zfilter_by_projectr,   r   r-   r/   r0   lists_options_list  s4    

   zCmfTask.lists_options_listc                 K   sb   |sg }|r,| dd r,|dd| dgg}|ddddgdddggg}| j|f||||d|S )Nr   rS   rM   r   r  r  r5  )r  r9  r*   r8  r6  rR   rY   r   r,   r/   r/   r0   main_list_options_list  s    zCmfTask.main_list_options_listc                    s   |sg }|r,| dd r,|dd| dgg}| dd sR|ddddgdddggg}t j|f||dddgg|||d|}|r|d	 t| }	|	d
krt j|f||dddgg||d
|	gd|}
q|S n(t j|f||dddgg||d|}
||
 S )Nr   rS   searchrM   r   r   r  )r6  rR   rY   r   slicer   r   r9  r5  )r  r'   r7  r  )r*   r8  r6  rR   rY   r   r=  r,   ZepicsZend_cntZ	not_epicsr-   r/   r0   parent_task_options_list  sD         z CmfTask.parent_task_options_listc              	   K   s   |sg }|ddddgddd ggg}|rF| dd rF|dd| dgg}| dd }|r|dddd	| d	gd
dd	| d	gddd	| d	ggg}tjjf |||d|S )NrM   Z
cmf_hiddenrS   Fr   r<  r   r\  rj  r   r]  r  )r  r7   ZCmfComponentr(   r*   r8  r6  rR   rY   r   r,   r<  r/   r/   r0   components_options_list  s     4zCmfTask.components_options_listc                    sp   |sg }|dddgg}| dd }|sJ|rJ| dd rJ|dd| dgg}d|d< t j|f||||d|S )	Nr   rS   r   r<  r   TZinclude_hiddenr5  r  r'   r7  r?  r-   r/   r0   gantt_project_options_list  s    z"CmfTask.gantt_project_options_listc                    sd   |sg }|rF| dd rF| dd rF|dd| dgdd| dgg}t j|f||||d|S )Nr   r  rS   r5  rA  r:  r-   r/   r0   request_type_option_list	  s
    "z CmfTask.request_type_option_listc                    s  |dkr$| j |f||||d|S |dkrH| j|f||||d|S |dkrl| j|f||||d|S |dkr| j|f||||d|S |dkr| j|f||||d|S |dkr| j|f||||d|S |dkr| j|f||||d|S t j|f||||d|S )	Nrv   r5  )rM  affected_versionsr  rH   r   r   request_type)	r9  Zreleases_options_listr;  r>  r@  rB  rC  r'   r7  r:  r-   r/   r0   r7    sX           zCmfTask.field_options_listT)
system_jobc              	   K   sR  t d|  d|  |  d| }t|d }	d|	 }
tjj|
ddgd}|r|jd	krt d
 |j	
 |_|j  tj|dd  nd}|rtjj|dgd}d}|rtj|}d}|rtjj|}t d|j d|j d|  tj|
| | d|pd ||||d}|j  |  t d|j d|j d |jjS )u  
        Метод для автоматического создания задач.
        Переоткрывает задачу, если такая уже есть закрытая.
        Уникальность задачи определяется по topic + text.
        Дополнительную, переменную информацию, например параметры запроса, можно передать в extra_text
        z
Auto task z, info: /zutf-8zAuto-r   r   )r2   rY   r   zAuto task reopenu'   Переоткрываем задачуr   NZdefault_projectr   zNew auto task for r   z
) project 
rz  )r2   r   r   r}   r   rw   r?   r   )r  hashlibZmd5encodeZ	hexdigestr7   r   r  r   r@  rA  r   r   r   rh   r@   rk  r[   rY   r   Zget_obj_by_tuuid_strr   r2   r6   r^   )r   r   Z
extra_textrw   r   Zcmf_owner_idr   _kwargsZtask_keyZ	task_hashZ	task_coderL   r}   r   r?   r/   r/   r0   	auto_task*  sD    


  
zCmfTask.auto_taskc                 O   s   t jjdddgd}dddg}dddg}|r:dd|jgg t }|D ]P}t jjdd|jgdddggd}	t jjdd|jgd}
||jj	|	|
d qD|S )	Nri  rO   Tr:  r   r5  r   )Zin_progressr   )
r7   rk  r(   r6   r  r   r1   r   r&   r^   )r*   rR   r+   r,   ZpersonsZin_progress_filterZcount_filterrm  resultZin_progress_countr   r/   r/   r0   get_responsibles_tasks_countW  s    

z$CmfTask.get_responsibles_tasks_countc                 C   sf   | j jsB| jjsB| jjsB| jjsB| jsB| jjsB| jjsB| jjsBd S | jjrT| jrTd S | j	
| | _d S r   )r   r|   r?   r   r@  r   rv   r{   r  	scheme_wfcalc_workflowr   r/   r/   r0   r   g  s(    
zCmfTask._calc_workflowc                 C   s\   | j jsd S | jdkr6| jjr6| jjdkr6tddd | jjdkrX| jdkrXtddd d S )Nr   ua   Нельзя изменить Логический тип задачи на Гант-проектTrC   uT   Нельзя изменить Логический тип у Гант-проекта)r{   r|   r   r   rW   r   r/   r/   r0   r  {  s    z%CmfTask._calc_logic_type_change_guardc                 C   s\   | j js8| jjr&| jdks8| jjdks8| jjr4| js8d S |   tt	j
jd| jjid d S )Nr  r   r  r  )rH   r|   r{   r   r   r   rC  r"  r  r7   r   _recalc_gantt_path_deferredr6   r^   r   r/   r/   r0   r     s    
	zCmfTask._calc_gantt_pathr  )	only_onceonly_once_argsc                 C   s6   t jj| dddddgd}||j |jdd d S )	NrH   r  r
  r   cache_branch_gantt_pathrW  TrJ   )r7   r   r  r#  rH   r@   )r  tr/   r/   r0   rQ    s
    z#CmfTask._recalc_gantt_path_deferredr   c              
   C   s  |dkrt ddd |r||ddddg | j|jkr>|j| _| j|jkrR|j| _|jd	krj|| _d | _q|jd
kr|| _nd | _d | _tjj| ddddddddgdD ]}d}| jd
kr| |_| j|_d}nP| jd	kr| |_d |_d}n4|j| jkr| j|_d}|j| jkr| j|_d}|jrF|	|  |j
j|j
jkrFd}|rX|jdd |jrt|j| |d d q||  qd S )Nd   uM   DEV: Защита от рекурсии: _recalc_gantt_path: if r_count > 100TrC   r  r
  r   r   r  r   rT  rH   rC  r?   rH   rY   FrJ   r   )rH   r_count)rW   rU   r  r
  r   r7   r   r(   rC  r"  rT  r   r   r@   r#  _check_relations)rj   rH   rX  ZchZ	need_saver/   r/   r0   r#    sZ    

   


zCmfTask._recalc_gantt_pathc              
   C   s   dd l }tjjj }tjt	j
|}| j|d}|j|D ]b}t|}|| }W 5 Q R X tjj||d d}	tjd|d d|	j d|d	}
|
  q>d S )
Nr   r  r   )r?   r   rH  Zauthoru   Вложение u    было изменено)r1  
cmf_authorr   r?   )yamlr7   ZCmfRFiler_   Zdata_driverZget_rdr<  pathjoinZconfigZ
DIRTY_PATHr  ioZ
io_iterdirr3  Z	safe_loadreadri   r   rh   r   r@   )r*   r  r[  rdiskZ
dirty_pathr4   Z	file_pathr   Z	file_dataZattachrt   r/   r/   r0   process_dirty_attach  s    
zCmfTask.process_dirty_attachc                 C   s   | j s*| jdkr*d | _| jjr&|   d S |sB| ddg | j}|sPg | _d S |jj}|d krltddd ||j	j|j
j|jj|jjdf| _| j	jdd	 | jD krtd
| j d|j ddd | | d S )Nr  #parent_task.cache_branch_gantt_pathr  zODEV: WARNING: _calc_cache_branch_gantt_path: if cache_branch_gantt_path is NoneTrC   )r6   r2   r   r   c                 S   s   g | ]}|d  qS r  r/   r   rU  r/   r/   r0   r     s     z9CmfTask._calc_cache_branch_gantt_path.<locals>.<listcomp>ul   Произошло зацикливание! Попытка добавить дочернюю задачу "uK   ", которая уже является родительской для "rX  )rC  r   rT  rH   r|   rY  rU   r^   rW   r6   r2   r   )rj   rH   rT  r/   r/   r0   r"    s2    z%CmfTask._calc_cache_branch_gantt_pathc                 C   st  |rt |nt  }|s(| dg | j}| jrB|dd | jD B }| jst|rt|jrf|dd |jD B }||jj t	d| j
j d|  |rddd	d
ggddd| gdd| ggg}ddg}tjj||dD ]L}|jjj| jjkr|jn|j}|jj|krtd|j d|j
 ddd qdddgdd| gg}dddg}tjj||dD ]"}	|	j}
|
j|| jjhB d qLd S )Nrb  c                 S   s   h | ]}|d  qS r  r/   rc  r/   r/   r0   r    s     z+CmfTask._check_relations.<locals>.<setcomp>c                 S   s   h | ]}|d  qS r  r/   rc  r/   r/   r0   r    s     z&cmf_task._check_relations, task_code: z, parent_tasks: r  r  zsystem.finish:startzsystem.finish:finishrM   rP   rO   rN   r   u   Невозможно перенести задачу из-за того, что существует связь ОН/ОО у задачи "z" u?   . Удалите связь и попробуйте снова.TrC   r  z,out_link.parent_task.cache_branch_gantt_pathz out_link.cache_branch_gantt_pathzout_link.has_child_tasksrY   rR   )
gantt_path)r   rU   rH   rT  rC  r:   r6   r^   r9   r   r2   r7   rb   r(   rN   rP   rW   r   _check_additional_relations)rj   rH   re  rl  _fieldsro   rL   Zadditional_child_filterZadditional_child_fieldsZadditonal_child_relationZadditional_childr/   r/   r0   rY    s<    
 zCmfTask._check_relationsc                 C   s   |dkrt ddd |r t|nt }| j| j|d dddg}tjj| |d	D ]B}|jrx|j|| j	j
hB |d
 d qP|j|j|| j	j
hB d qPd S )NrV  u_   DEV: Защита от рекурсии: cmf_task._check_additional_relations: if r_count > 100TrC   )rH   re  rb  rT  rC  rW  r   )re  rX  )rW   r   rY  rH   r7   r   r(   rC  rf  r6   r^   )rj   re  rX  Zchild_fieldsr  r/   r/   r0   rf  -  s    z#CmfTask._check_additional_relationsc                 C   sR   |  ddg tjjdd| jgdd|jggd}|sNd| _|   | jd	d
 dS )u   
        Убирает метку дерева у родительской задачи при удалении или перемещении дочерних задач
        rC  r   rH   rS   r6   r9  r:  FTrJ   N)rU   r7   r   r   r6   rC  r"  r@   )rj   r  Zhave_childrenr/   r/   r0   r  A  s    "zCmfTask.child_task_deletec                 C   s~   | j jsdS | j jrV| ddg | j jsVd| j _| j   | j jdd | j j  | j j	rz| j | j j	ksz| j j	
|  dS )u   
            Рассчет has_child_tasks
            должен вызываться после _calc_parent_task
        Nr  zparent_task.op_gantt_taskTrJ   )rH   r|   r  rU   rC  r"  r@   r]   Z$task_has_child_tasks_is_changed_hookr   r  r   r/   r/   r0   r   L  s    
z)CmfTask._calc_parent_task_has_child_tasksc                 C   s  | j js| jsd S | jr.| jr.| jj r.d S d }| j r&| j jr&| j jjr&t	
| j jj}| j jjr| dd dD  | j jj}| j| d|j d}tjj| |d nr|jr&| j|jkr&|j| jkr&|jddd	d
ddg | j|j d|jj d|j d}tjj| |d | j jr
| js
| j j}|ddg |jr
|jjr
t	
|jj}|jj}|r||kr| j| d|j d}tjj| |d nX|jr
| j|kr
|j| jkr
| j|j d|jj d|j d}tjj| |d d S )Nc                 S   s   g | ]}d | qS )zresponsible.primary_role.r/   r   r/   r/   r0   r   k  s     z1CmfTask._calc_structural_list.<locals>.<listcomp>)r   r   ordernor  r  r   uU   SimpleLogic: Задача добавлена в структурный список "uG   " т.к. он указан в должности исполнителяr   r   r   rh  r  r  r   u>   SimpleLogic: Задача добавлена в список "r  u   " т.к. он является Структурным проектом Главной роли ответственного по задачеz"primary_role.structural_project_idz$primary_role.structural_project_listuS   SimpleLogic: Задача убрана из структурного списка "uX   " т.к. он указан в должности прошлого исполнителяu<   SimpleLogic: Задача удалена из списка "u   " т.к. он является Структурным проектом Главной роли прошлого ответственного по задаче)r}   r|   r   r   rz   rv   r   r   Zstructural_project_idr   r   Zstructural_project_list_idrU   Zstructural_project_listr~   r   r7   rh   r   r  r   r6   r   rP  r?   )rj   Zappend_structural_project_listr   r  Zold_responsibleZremove_structural_project_listr/   r/   r0   r  ^  sT    

zCmfTask._calc_structural_listc                 C   sp   | j s&| jjs&| jjr"| jjd ks&d S | jrlt| jjtjrlt	| j
}| jjd krl|jjd k	rl|j| _d S d S r   )r   r?   r|   r  r^   r   r7   r   r   r   r   Zdefault_agile_story_pointsr   r/   r/   r0   r    s    "z CmfTask._calc_agile_story_pointsc                 C   s@   |  ddddg t| jp$t| j| _| jjr<| jdd d S )Nrv   has_related_tasksin_tasks	out_tasksTrJ   )rU   r  rj  rk  ri  r|   r@   r   r/   r/   r0   has_related_tasks_hook  s    zCmfTask.has_related_tasks_hookc                 C   s   | j jsd S | dg | jr8| j | jjkr8tddd | jddg | jjr`| jj| j jkr|| jjs|| j | j_| j	  d S )Nzbp_gantt_task.sched_worku   DEV: FATAL: нельзя изменять поле estimate_work, когда существует базовый Гант-планTrC   r  
const_work)
r  r|   rU   Zbp_gantt_taskr  rW   r]   r   rm  r@   r   r/   r/   r0   r    s    
zCmfTask._calc_estimate_workc                 C   s   |  dddg | jf |}tj }|jd |d |_| jrJ| j|_d|j_|	  |j
dd tjj|d| j d| j d	 |jjS )
u    Создание задачи из шаблона
        :param self: Шаблон документа
        :param params: Параметры для шаблона
        :return: Идентификатор новой задачи
        tmplt_document.textrv   r   r   z%d.%m.%YTrJ   u0   Задача создана из шаблона r   )rU   create_from_templater   r   r   strftimerv   r?   r|   r   r@   r7   rh   r   r2   r6   r^   )rj   r  new_taskZnow_dater/   r/   r0   r     s    
 z!CmfTask.create_task_from_templatec                    s&   | j dgd | jdkrdS t  S )uB    Шаблон уведомлений для разных workflow r   r   ztask.ticketzhelpdesk_mail_notification.html)rU   r   r'   +get_default_mail_notification_template_namer   r-   r/   r0   rr    s    
z3CmfTask.get_default_mail_notification_template_namec                    s   | j rtj| jj d S | | j tj| j	jp6d|d< | j
rN| j
jjpPd|d< |d  dddd | jD  7  < t jf |S )Nrz  Zobj_result_textZobj_responsible_namesr   c                 S   s   g | ]}t |jpd qS )rz  )r;   r   )r   rr/   r/   r0   r     s     z-CmfTask.full_search_index.<locals>.<listcomp>)r8   r7   ZCmfFullSearchZ
mark_cleanr6   r^   rU   Zfull_search_preload_fieldsZ
strip_htmlr  r}   r   r]  r  r'   full_search_indexrj   r,   r-   r/   r0   rt    s    &zCmfTask.full_search_index   Добавленоc                 C   sR   |d krt j}nt|tr(tjj|d}tjj| |||||d}| j	d|d |S )Nr  )Z
start_dater   r  )r  )
r9   r  r   r;   r7   rk  r  r  Ztimetracker_task_change_timer   )rj   r  r	  r   dater   r  r/   r/   r0   r     s    

  zCmfTask.timetracker_change_time   )rR  rF  rw   c                 K   s   t j|  d S r   )r7   r   _recalculate_codes)r   rK  r/   r/   r0   recalculate_codes_celery  s    z CmfTask.recalculate_codes_celeryc                 C   sv   d}d}t jjdd| gddg||| gddd}||7 }|s@d S |D ]$}|jsPqD|jdd |jdd	 qDt  qd S )
Nr      r=   rS   r2   T)rR   rY   r=  rI   r#   )from_recalculaterJ   )r7   r   r(   r=   
_calc_coder@   Zcommit_with_event)r   r  limitZ
task_slicerL   r/   r/   r0   ry    s$    
zCmfTask._recalculate_codesc              	      sP  t  < tjj| d}|s4td W 5 Q R  dS td|  tjj|dgd}tdt|  dd	  t	| fd
dd}d}|D ]}|d7 }td|  |rtj
j|dD ]}|  q|jjdd  d| }tj
jdd|gddr.td| d |d7 }|jjdd  d| }q||_|jdd qW 5 Q R X dS )u  
            Метод для ручного запуска.
            Пересчитает номера в кодах задач начиная с единицы.
            ! Прошлые коды задач не сохраняются
            ! Пошлые коды задач удаляются
            Если код занят задачей из другого проекта - он пропусается
        r  u   Проект не найден!NuY   Удаляем историю выдачи кодов задачам из проекта r2   )r=   rY   u   Всего задач: c                 S   s   z
t | W S    Y dS X d S )Nr   )r   )r  r/   r/   r0   tryint<  s    
z:CmfTask.reindex_project_tasks_code_numbers.<locals>.tryintc                    s    | j jdd S )Nr   rH  )r2   r^   
rpartition)rU  r  r/   r0   <lambda>C      z<CmfTask.reindex_project_tasks_code_numbers.<locals>.<lambda>)r   r   r   u'   Обрабатываем задачу: )rL   r   rS   TrQ   u   Код u    занятrJ   )ru  Zdisable_notifyr7   r   r  r  r   r(   r  sortedr  r`   r2   r^   r  r   r@   )r   Zwith_history_deleter=   r
  r  rL   ZhistZnew_coder/   r  r0   "reindex_project_tasks_code_numbers*  s0    	
z*CmfTask.reindex_project_tasks_code_numbers<   )rR  Zsoft_time_limitrF  rw   c               	   K   s   t j}d}d}|jddgdD ]}|d7 }|jdd|gd}|j|kr|d7 }td	|j d
| d|j  ||_|jdd |jj	|jj	d}t
d|j | t
d| |d dkrt  qtd| d| d |S )u   Актуализация кеша кол-ва задач в епике (нужно ли для подпроекта? Вроде как нет).r   r   r  )r   rY   r   rH   rS   r:  zUpdate cache_members_count z -> r   TrJ   )Znode_idZelements_countztree-node-count-changes-ztree-node-count-changesrV  zRecalculate rG  z lists caches)r7   r   r(   r   r  r9   r   r6   r@   r^   Zcmf_emit_event
cmf_commit)rK  r*   Ztotal_countZ
calc_countZcmf_epicZ
real_countZ
event_datar/   r/   r0   r  W  s$    
 
zCmfTask.recalculate_cache	recursion)r  c             	      sX   t  }| dddddddg | jr<|| jj|d d	}t j|d
|i||S )Nzfollowers.personzfollowers.person.cmf_deletedzfollowers.person.does_not_workzfollowers.notify_volumezfollowers.follow_childrenr   rH   r   r  r  )r   rU   rH   unionget_all_followersr'   )rj   r  r+   r,   rs   r-   r/   r0   r  r  s    
   zCmfTask.get_all_followersinline_save)tmp_objcreate_formui_form_moderY   c             
      s|   | j |ddddddddgd	d
|}|jrX|jjdkrXd}t j|||||d|S |p`|j}t j||||d|S )Nr{   r   zproject.ui_form_schemezproject.cust_field_conf_schemezproject.logic_prefixr  r8   rE  T)rY   rI   r0  r  )r  r  r  rY   )r  r  rY   )r   r=   r   r'   r    r8   )r*   r  r  r  rY   r+   r,   r-   r/   r0   r    z  s(          
zCmfTask.ui_getc                    s<   t  |}t|dd r8tjj|jjd}tj||_|S )Nr]   r  )r'   get_automation_ui_formr  r7   r  r   r]   r6   )r*   r4   ui_formr]   r-   r/   r0   r    s
    zCmfTask.get_automation_ui_form)
ui_form_idr  c                 C   s   t j|S r   )r7   	CmfUiFormZget_ui_group_fields)r*   r  r/   r/   r0   _get_ui_group_fields  s    zCmfTask._get_ui_group_fieldsc                    sh   t t|j}|p|j}|rR|jdkrR|sR|jrRtjj	|jdgd}|j
rR|j
}t j|||||dS )Nr0  zui_form_view_inner.ui_form_jsonrW  )tmp_is_public_formtmp_ui_view_formr  r  )r   r   r;   r   r8   r   Zrequest_type_idr7   ZCmfSDeskRequestTyper   Zui_form_view_innerr'   _build_ui_form)r*   r  r  r  r  r  Ztmp_projectrE  r-   r/   r0   r    s"    

    zCmfTask._build_ui_formc                 C   s   t jjddgddS )u   
        Экран по умолчанию если нет никаких правил и схем экранов

        Returns:
            CmfUiForm: системный экран по умолчанию
        zui_form.task:defaultui_form_jsonT)r2   rY   cache_inmemory)r7   r  r  r   r/   r/   r0   _get_default_ui_form  s    zCmfTask._get_default_ui_form)copy_attachmentscopy_relationscopy_subtaskscopy_alldeferred
new_parentlevel
copy_lists)r   r  r  r  r  c       	            s  |r>|s>|r|j jnd }t| j| j j||||||dd d S td| j  d|  |rjd}d}d}d}	| dddd	d
dddddddg t j|
||d|}| j	s|j
jdd|_d |_tjjddd}|rbdd|gg}tjj|dd| gg dgdD ] }| }||_|jdd q tjj|dd| gg dgdD ] }| }||_|jdd q@| j	s~tj| ||d  | jjr| jjr| jj}n| jj}|jpd|j |_|jr|sd |_| || |r||_d |_	|	rd!d" |jD |_ng |_d|_d|j _!|  |rntj"jd#d| gdd$}|D ],}|j|j#jd% |||||||d& d' q@|d(kr|j$%  ttj&j'd)t(|j id | j)r| *| |S )*N)r  r   r  r  r  r  new_parent_idr  zcopy_task: task_id: z	, level: T**zattachments.urlr  rv   r  r  zattachments.url_previewzattachments.url_preview_imgr  rn  ztmplt_document.text_renderrA   )r   r  r  r  zsystem.clone)r2   r  relation_typer9  rN   rO   r   )Zfrom_task_copyrP   )rN   rP   r  rz  Fc                 S   s   g | ]}|j d kr|qS r6  r7  r8  r/   r/   r0   r     s     
 z CmfTask.copy.<locals>.<listcomp>rH   )rR   Zinclude_templatesu    Копияr   )r   Zcopy_attachmentr  r  r  r  r  r  r   r  )+r6   r^   r  copy_task_with_subtasksr9   r   rU   r'   r   r   r@  rA  r   r  r7   ZCmfRelationTyper  rb   r(   clonerN   r@   rP   tmplt_documentr  Ztext_renderr   rC  _clone_op_gantt_taskrH   rv   r   rO  r|   r   r   r]   Ztask_copy_hookrg   r  r;   rA   _copy_checklists)rj   r   r  r  r  r  r  r  r  r  r+   r,   r  new_objZ
clone_typerl  r/  Znew_relationZ
tmplt_textZsubtasksrk   r-   r/   r0   r     s        










zCmfTask.copyc                 C   s   | j D ]}|j|d qd S )NrT   )rA   r   )rj   r?   r  r/   r/   r0   r    s    
zCmfTask._copy_checklistsu!   Копирование задач)rR  rS  descriptionZshow_bg_progressbarc           	   	   C   sL   t jjdd| gd}||  t jj|d}|j||||||dd d S )Nr6   rO   r:  r  T)r   r  r  r  r  r  r  )r7   r   r  rU   rV   r   )	r  r   r  r  r  r  r  rL   r  r/   r/   r0   r    s    
   zCmfTask.copy_task_with_subtasksc                 C   s   |j dg |j  |_ |js0|j jr0d|j _d|j _d|j _d|j _d|j _d |j _	d |j _
td|j _td|j _||j _|r||j _|j jdd d S )Nr  r   z0.00TrJ   )r]   rU   r  rC  Zagregat_workr  Zactual_durationZactual_completeZactual_myself_workZactual_start_dateZactual_finish_dater   Zactual_costZactual_myself_costrL   rH   r@   )rj   r  r  r/   r/   r0   r  )  s     zCmfTask._clone_op_gantt_taskc                    s2   |  dg | jdkr*d| j d| j S t jS )Nr   r  zproject/rG  )rU   r   r  r2   r'   hrefr   r-   r/   r0   r  ;  s    
zCmfTask.hrefc           	      K   sz   t t}d}d}| j|dddg|| |d | gd}|D ]"}|jD ]}||j  d7  < qDq:t||k rlqv|d7 }q|S )Nr   i  --r6   zlists.idr   )rR   rY   r=  )r   r   r1   rv   r6   r  )	r*   rR   rK  rM  ZpageZ	page_sizer
  rL   r  r/   r/   r0   r   C  s      

zCmfTask.count_tasks_by_listsc                 C   sl   | j s| jS | dg t| j }| jr6| jj  |rd|jrd| jrd| jjrd|j	j
d | jjj
 S |j	j
S )Nzlogic_type.obj_code_prefixr   )r   Zcode_prefixrU   r   r   r{   Zobj_code_prefixr   task_code_use_logic_type_prefixZtask_code_prefixr^   r   r/   r/   r0   get_code_prefixS  s    
zCmfTask.get_code_prefixc              
      s   t   }dd l}| }d}d}tjjdd|gddr|d7 }t   }||k sjtd| d	| j d
| | }|dkr"td|dd| j d| j	 dd| j
ko| j d	 q"|S )Nr   i'  r2   rS   TrQ   r   u8   Превышен лимит поиска кода limit=z model=uA   , возможно надо отключить def gen_code: passz$!!! --- gen_code::duration too long z.1fz sec, r   z, r   )r'   gen_codetimer7   r  r   AssertionErrorr   r  r6   rY   r2   )rj   r2   r  startr~  r  Zdurationr-   r/   r0   r  m  s    

 .zCmfTask.gen_codec                    s
  | j r| jjs| jjs|sd S | j s2t   d S | j rH| j drHd S d }d }| jrbt	| j}| jjr| jj
rt	| jj
j}|r|  }| j j| dr| j jd|dkr| j j}|rtjj|dstj|| |d}|  d| j_t   d S | jjr|| j j|   ds|| j j}| jsh|rhtjj|dshtj|| |d}|  d | _ t   d S | jjr|r|jr| j j|   ds| j j}| js|rtjj|dstj|| |d}| jjr||_|  t   d S )NzA-r   )r2   )r2   rL   r=   T)r2   r=   r|   r{   r'   r}  r   r   r   r   r   r6   r  r^   r   r7   r  r   r@   r   r  )rj   r|  r=   r  
new_prefixZ	prev_codeZcode_historyr-   r/   r0   r}    sl    
.
$


zCmfTask._calc_coderd  c             	   O   sl   |sg }|sg }| j |||d|}g }|D ]8}z|jdd || W q. tk
rd   Y q.Y q.X q.|S )Nrd  T)ZTEXKOM_skip_failread_audit)r(   Z_acl_check_readr~   ZCmfPermissionError)r*   rY   rR   r+   r,   Zres_uncheckedrs   rs  r/   r/   r0   r!     s    zCmfTask.public_listc                    s   d|d< d|d< t  jf |S )NFZwith_parent_ownerZinherit_executors)r'   r   ru  r-   r/   r0   r     s    zCmfTask.all_relation_personsc                 C   s<   | j j  | j jj}| | jj|  | | jj| d S r   )r]   r  r   r^   #_update_actual_work_for_all_parentsrH   r   r   )rj   actual_work_timer/   r/   r0   _update_actual_work  s    
zCmfTask._update_actual_workc                 C   sT   |sd S |j   |j j  |j  j|7  _|j jdk rBd|j _|j jdd d S )Nr   F)Z
user_input)r]   r   r  r@   )rj   rL   r  r/   r/   r0   r    s    
z+CmfTask._update_actual_work_for_all_parentsc                 C   s$   | j jddd}|s | j dS d S )Nr3  Fr4  r  )r@  rA  )rj   Zdefault_statusr/   r/   r0   _get_default_open_status  s    z CmfTask._get_default_open_statusz@hourly)rR  rF  Zschedulec                  C   s  t d ddddgdddggdd	d
ggddd gddtjjtjjdgg} tjj| dddddddddddddgdD ]L}|j	r|
 }t d|  |jjr|jj|_| |_|j  |j|_d |_d |_|  |  |jd
d qtt d|  |jdkr|jjdkrJ|jj}|  |jr|j|jkr||_q|jjr^|jj|_|jrx|jjdd|_| |_|  qt|jjdkrt| |_|jjdk r|j  |  qtd S ) Nz(Run CmfPerson.cron_celery_check_periodicrM   zstatus.coder9  r3  r   r5  period_create_newrS   Tperiod_intervalperiod_next_datez<=ry   r  r   r@  period_clear_checkboxr   rn  rx   r   r   z6CmfPerson.cron_celery_check_periodic: create new task rJ   z2CmfPerson.cron_celery_check_periodic: reopen task )r   r2  r   ztox-checklist--checkedrz  pause)r9   r   r   r   r   r   r7   r   r(   r  ro  r  r  r   r  r   r   r   rx   r  r  r@   Z_cacl_next_periodr   rK  r^   r  rv  r2   )rl  rL   rq  Zold_deadliner/   r/   r0   cron_celery_check_periodic  sf    
      









z"CmfTask.cron_celery_check_periodicc                    sd   |    |   |   |   |   |   |   | jjrJ| j	
  |   t j|| d S r   )r   r   r   r   r   r  r  rH   r|   r]   r  r  r'   _save_importr   r-   r/   r0   r  G  s    
zCmfTask._save_importc                    sB   t  |}|s>|t  dddg |tjdddg7 }|S )NrZ  rJ  rG  r  rP   rN   )r'   import_shop_fieldsr  r7   rb   )r*   Zfields_namers   r-   r/   r0   r  T  s    zCmfTask.import_shop_fieldscsvc              =      s   |sddddddddd	d
dddddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=g=}t jj D ]}|d>r|| qt ||||S )?Nr6   r2   r   r   r  zcmf_author.namezcmf_author.loginzcmf_owner.namezcmf_owner.loginzparent.namezworkflow.namezlogic_type.namezstatus.namer   zcompany.namezresponsible.namezresponsible.loginzexecutors.namezexecutors.loginzspectators.namezspectators.loginr  zattachments.namezactivity.namez
lists.namezgit_repos.namezgit_branches.namezgit_merge_requests.namezgit_commits.namezrequest_type.namer  z op_gantt_task.actual_finish_datezop_gantt_task.actual_durationr  zop_gantt_task.sched_start_datezop_gantt_task.sched_finish_dater  zop_gantt_task.perform_workr  rw   rH   rJ  r  r   r  r
  r  r  rG  r/  r  rx   r  r   rM  rD  zop_gantt_task.actual_costzop_gantt_task.actual_completez#op_gantt_task.duration_is_estimatedr   r  Zcf_)r7   r   rY   r  r   r~   r'   export2file)r*   field_namesZbqlZformat_fileZinclude_archivedrl   r-   r/   r0   r  d  sz                                         
zCmfTask.export2file)id_listrY   c                 C   s\   g }| j dd|gdgdD ]}||jj|dj q|rX|| jdd |D |d |S )Nr6   r  r  r   r   c                 S   s   g | ]
}|j qS r/   r  r8  r/   r/   r0   r     s     z8CmfTask.group_changes_list_recursive.<locals>.<listcomp>)r(   r  r   r   r^   r   )r*   r  rY   ZchildrenrL   r/   r/   r0   r     s    z$CmfTask.group_changes_list_recursive)	subgroupsr  c                 C   sn   |D ]d}| |d |d |d |d d}|  |}t |d< |d  D ]\}}|drH||d |< qHq|S )Nr   r  r  r=   r?   r{   r   r  Z	ui_fieldsrequired)r  r  r   r  )r*   r  subgroupr  r  rl   metar/   r/   r0   r     s    


z%CmfTask.group_changes_required_fieldsc                 C   sj   |D ]`}| |d |d |d |d d}t j||d< |d ||d< t jj|d jjd|d< q|S )	Nr   r  r  r  rO  r@  )Zworkflow_idZstatus_list)r7   ZCmfSchemeWfZcalc_schemerP  ZCmfWorkflowZget_status_listr6   r^   )r*   r  r  r  r/   r/   r0   r     s    zCmfTask.group_changes_statusesc                 C   s*   ddl m} | jjsd S || jj| _d S )Nr   )markup_html_clean)Zcmf.util.cmf_clean_textr  r  r|   r^   )rj   r  r/   r/   r0   r     s    zCmfTask._clean_result_textc                 C   sX   | j rT| jsT| jrT| ddg | jj}|D ]&}|jdks,|jdkrFq,| j| q,dS )ux   Устанавливаем для dummy task теже спринты, что и у родительской задачиzparent_task.lists.logic_prefixz#parent_task.lists.cache_status_typer  r   N)r   rv   rH   rU   r   r   r~   )rj   Zparent_task_listsZparent_listr/   r/   r0   r     s    z#CmfTask._set_lists_from_parent_task)r  r  r  r  c                 C   s\  t jj| dgd}t jjdd|gd}t jjdd|gd}t }|g}td|   g }t jjdddgd	d|gd
ddggd}	d}
|	D ]}|j|krt	d|j  q|
|j |
d7 }
d}|D ]}||jkr|j| d}q|D ]}||jkr|j| d}q|sq|jdd |
d dkr2t  |jr|| qt  |}|sFqXqFdS )u  Синхронизация изменённых спринтов у подзадач

        Args:
            task_id (str): ИД родительской задачи, у которой поменялся lists
            sprints_to_add_ids (list): ИД спринтов для добавления в lists
            sprints_to_remove_ids (list): ИД спринтов для удаления из lists
        rv   r   r6   r  r:  z)deferred_job(_sync_subtask_sprints) task:rC  r8   rH   r   r9  r   rd  r   zjob FAIL RESURSION r   FT)r  r  N)r7   r   r  rO  r(   r   logginginfor6   errorr:   rv   r~   rP  r@   r  rC  )r  r  r  rL   r  r  Zprocessed_task_idsZprev_lvl_task_listZnew_lvl_task_listZsub_tasks_listr  Zsub_taskr  Z	sprint_idr/   r/   r0   r    sN    



zCmfTask._sync_subtask_sprintsrY   forcec                    sT  d}t |pg }g }d|kr,dg}|d | || ttddd}dtttt d fdd	  | }||krt jf ||d
|S t 	 }	dt
|	fg}
|
rP|
 \}}|	|| }fdd|D } || }| |}|||krt jf ||d
| qt
|dkrZ||| d  }|
||f |
||f q|d }| }t|tr||st jf ||d
| qt |	 }d}|t
|k ri }|t
|k r"|| }|||| i}||i} || }| |}|||kr|rq"|}|d7 }q ||i| }t jf ||d
| qq| S )u  
        Загружает поля модели с учётом лимита PostgreSQL (макс. 1600 колонок в SELECT).
        Если план запроса превышает лимит, то он дробится по верхнему уровню,
        а в случае «тяжёлого» ключа — по вложенным под-ключам.
        Поддерживается мета-параметр '--', отключающий добавление авто/служебных полей.
        i@  r  )treer  c                 S   sL   d| g }}|rH|  }| D ]$}|d7 }t|tr |r || q q|S )u  
            Подсчитывает общее количество узлов в плане (все ключи и под-ключи).
            Это нужно, чтобы не превысить лимит PostgreSQL в 1600 колонок.
            r   r   )popr   r   r  r~   )r  totalstackdr   r/   r/   r0   count_nodes
  s    z(CmfTask.load_fields.<locals>.count_nodesrz  )planprefixr  c                    sT   g }|   D ]B\}}| | }t|trD|rD| ||d  q|| q|S )u  
            Превращает план (dict вложенной структуры) в список строк
            вида "field.subfield.subsubfield".
            Используется для передачи в _build_load_plan и load_fields.
            r{  )r   r   r  r  r~   )r  r  outr   r   p)flattenr/   r0   r    s    z$CmfTask.load_fields.<locals>.flattenr  r   c                    s   i | ]}| | qS r/   r/   )r   r   )	full_planr/   r0   
<dictcomp>6  s      z'CmfTask.load_fields.<locals>.<dictcomp>r   rH  )rz  )r(   rP  Z_build_load_planr  r   r;   r
   r'   rU   r  r  r  r~   r   )rj   rY   r  r,   ZLIMITZincomingZ
meta_extrar  ZrulesZtop_keysr  r   rs  Zsubset_keysZsubplanZrebuiltmr   innerZ
inner_keysr  Z	cur_innerZikZ
test_innerZtest_wrappedZ
test_rulesZtest_rebuiltZ	sub_rulesr-   )r  r  r0   rU     sd    


zCmfTask.load_fieldsc                 C   s   | j js| jsdS tjjdd| jggdddgd}|s:dS tjjdd	| jgd
d|ggd
gd}dd |D }t	|| }|D ]*}|j
dkr|jtjkrq|tj||  q|dS )u:   Создание чек-листов из шаблоновNZdefault_for_logic_typesr  r   
view_scoper   r   r?   rS   from_templatec                 S   s   h | ]
}|j qS r/   )r  )r   r  r/   r/   r0   r  {  s     z+CmfTask._calc_checklists.<locals>.<setcomp>r2  )r{   r|   r   r7   ZCmfChecklistTemplater(   r  ZCmfChecklistr6   r   r  r   r9   r'  Zcreate_checklist)rj   Z	templatesZexisting_checklistsZusing_templatesZtarget_templatestemplater/   r/   r0   r   j  s*    zCmfTask._calc_checklistsc                 O   s   |  dg dt| jiS )Nr  Zapprovers_count)rU   r  r  r   r/   r/   r0   r"     s    zCmfTask.count_approvers)NN)F)F)F)F)NNN)F)F)r  NN)N)NNNNN)NNNN)NNNNN)NNNN)NNNN)NNNN)NNNN)NNNNNN)N)N)r   )N)NN)Nr   )rv  NN)F)FNFN)N)F)N)NNr  F)N)NF)__name__
__module____qualname__modulesrL   rY   cmf_taskr   Zapi_methodsservicedeskr7   CmfTaskMixinclassmethodr(   r   r1   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r	  r   r  r  r  r   r  r"  r#  r*  r,  r0  r   rI  rQ  r   rT  rV  r   rb  rd  rn  rq  rx  r!  ry  r   r  r   r  r  r  r  r  rV   r  r  r  r  r   r  recompileASCIIr  r  r   r  r  r@   r  r  r   r  r  r  rX   r  r  r`   r  r  r  r)  r   r  r!  r  r  r  r3  r   r9  r;  r>  r@  rB  rC  r7  staticmethodZcmf_deferred_jobrL  rN  r   r  r   rQ  r#  ra  r"  rY  rf  r  r   r  r  rl  r  r   rr  rt  r   rz  ry  r  r  r   r  r    r  r;   r  r  r  boolr   r  r  r  propertyr  r   r  r  r}  r!   r   r  r  r  r  r  r  r  r   r  r   r   r   r   r  r
   rU   r   r"   __classcell__r/   r/   r-   r0   r      s&  
@";<
&'AL"
	A.  $S
 
+  *G{ 0!0	  A
 	$7	
	                                               +1
")?

,, "		      hJK
9"yr   )$r   r  collectionsr   r   decimalr   rI  Zredis.exceptionsr   r  Zwerkzeug.datastructuresr   Zdateutil.relativedeltar   Zcmf.includeZcmf.fields.base_fieldsr   Zmodules.task.fields.cmf_taskr  Z#modules.servicedesk.models.cmf_taskZcommon.models.cmf_active_entityr	   typingr
   r   r   r   r   r  r7   r  r  rL   rY   r   r/   r/   r/   r0   <module>   s    