U
    4hE                    @   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 G d
d dejjjjejjjjZdS )    N)defaultdict)	timedelta)Decimal)FileStorage)relativedelta)*)CmfTUUID)CmfActiveEntityc                       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dWdbdcZ1dXdedfZ2dYdgdhZ3dZdidjZ4dkdl Z5d[dmdn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d\ddZLdd ZMdd ZNdd ZO fddZPd]ddZQdd ZRdd ZSdddddZTdd ZUdddddZVdd ZW fddZX fddZYdd ZZdd Z[dd Z\dd Z]dd Z^dd Z_dd Z`dd Zadd Zbd^ fddÄ	Zcddń Zded_ fddǄ	Zeed`ddɄZfeda fdd˄	Zgedbdd̈́Zhedc fddτ	Ziedd fddф	Zjede fddӄ	ZkelemddՍdfddׄZneldgddلZoddۄ Zpdd݄ Zqdd߄ ZrdhddZsdiddZtdjddZudkddZvdd Zwdd Zxdd Zydd Zzdd Z{dd Z| fddZ} fddZ~dlddZelemdddddd Zeld d ZeldmddZelemdԐddd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dn fdd	Zedd Zdddddddddddddddeeeeed fddZdd ZelemdԐdgd dԐd!d"d# Zd$d% Ze fd&d'Zedod(d)Zd*d+ Z fd,d-Zdp fd.d/	Zeddd0d1d2Z fd3d4Zd5d6 Zd7d8 ZelemddԐd9d:d;d< Z fd=d>Zedq fd?d@	Zedred	 fdBdCZedseedDdEdFZeeedGdHdIZeeedGdJdKZdLdM ZdNdO ZelemeeeddPdQdRZdSdT ZdUdV Z  ZS (t  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*   r+   r   8   s    zCmfTask.countc                   s   |s| dd t j||S r   )r!   r"   slistr$   r(   r*   r+   r,   >   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
   r1   r-   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*   r+   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 )Nr3   
checklists   Не dummy task TabortTEXKOM_db_deleteparent_taskinclude_deletedr   Z	only_datataskrD   ORout_link==in_linkfilterrD   )r:   rD   r/   =r:   )r:   rD   Zinclude_dummy)load_fieldssave_preload_fieldsr3   	cmf_alertr1   _delete_checklistsr2   r
   r#   rC   r;   fields
issubclasscmfZ
CmfM2MBasesetattrop_gantt_taskvalueZ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*   r+   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rB| jj| _| jjrb| j| jjk rb| jj| _| jjrt| 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deadlineZtz)rP   cloned_fromr:   
logic_typerq   responsiblerp   appendrr   
alarm_datedatetimenowtimezoneutcset_now)rd   lZdeadline_minr*   r*   r+   #_save_dummy_task_sync_from_template   s8    
     




"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| _|   | j| j| j| jdS )Nr=   Tr>   Fu)   Выставлен код у dummy-task: )r1   r-   name	parent_id)save_preparer3   rR   r1   items
isinstancerV   rT   Z
CmfBackref
is_changedZ_load_changed_fieldsis_newr-   cloned_from_idr   rC   is_templater;   r   r   )rd   Zchanged_fieldskvr*   r*   r+   r      s0    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 )Nr=   Tr>   F)notifyemitaudit)!r3   rR   r1   r4   TEXCOM_ENABLE_GROWCACHE_HACKr7   _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"   rV   r2   ZCmfModelr;   rd   r(   r*   r+   _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 )Nr-   z
SIMILAR TOz
%-[0-9]+\Zr8   rN   -cmf_created_atT)rM   order_byrD   -)sget
project_idintr-   split)rd   Z
max_numberlastr*   r*   r+    _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   rY   
class_nameredislockacquirerelease
exceptionsZ	LockErrorr4   debugr   r   existsZincrr   set)rd   Zredis_dbsuffixkeyZlock_keyr   enext_code_numberr*   r*   r+   r   /  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:   rY   r2   
CmfProject_calc_list_plan_intervalrx   r   rR   captionrV   rT   CmfDateTimerz   plan_end_daterd   list_plan_start_date_minlist_plan_end_date_minr*   r*   r+   _calc_alarm_date_listM  s,    

$zCmfTask._calc_alarm_date_listc                 C   s   | j r| jjs| jjsd S | j jr&d S | jD ]6}|js<|jr,|jrP| j sP|j| _ |jr^|j| _ qdq,| j s| jr| jjjdkr| jj 	 r| jj | _ d S Nr   )
rv   r:   r   
componentsZdefault_responsibleZdefault_owner	cmf_ownerrY   r   load)rd   compr*   r*   r+   _calc_responsiblej  s.    

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j r| jr| j| _| jr|   | jr| jjs| j r| j| j k rtjr| j  d S r   )r   rx   r   statusrr   activityrp   plan_start_dater   r"   _calc_alarm_dater:   rY   r   Zauto_alarm_dater   r   rz   r4   import_moder}   r   r(   r*   r+   r     sR    


zCmfTask._calc_alarm_datec                    s$   | j r| jr| j  t j||S N)r   r   rx   r}   r"   _save_templaterd   r&   r'   r(   r*   r+   r     s    
zCmfTask._save_templatec                    s   | j jr| j rdS | js<| jjs<| jjs<| j js<| j js<dS | jjrl| jrlt| jdrl| jj  rl| 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   rT   r   )r   r   r   r:   rp   is_nullhasattrr   newoldr"   r   )rd   Ztmp_activityr/   r(   r*   r+   r     s6    

zCmfTask._calc_activityc                 C   s   d S r   r*   r   r*   r*   r+   _calc_parent  s    zCmfTask._calc_parentc                 C   s   | j | j jkrd S | jrH| j s&d | _n| j j  | j j| _| jdd | j  tj	j
dd| gddgd}|D ] }|j | j krp| j |_ |  qpd S )NTrE   rC   rN   r:   rX   rM   rT   )r:   r   gantt_projectmain_gantt_projectr   r;   rX   Ztask_parent_is_changed_hookr2   r
   r#   )rd   child_tasksrG   r*   r*   r+   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
| |d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r8| jjjr8| jjj}| jjj}|r| jspd}|| _t	j
| |dd  |   d S |rd}|| _t	j
| |dd  |   d S d S )Nr:   logic_prefixtask.gantt_projectu   SimpleLogic: в задаче установлен проект равный проекту родительской задачи   r:   text	log_levelr   cmf_owner_assistantsr   r   8responsible.primary_role.structural_project.default_listz1responsible.primary_role.structural_project_forceu   SimpleLogic: Задача добавлена в Структурный проект Главной роли исполнителяu   SimpleLogic: Проект сменен, т.к. в Главной роли исполнителя указано менять проект)tree_parentr   rv   rC   r:   r   rP   r   r   r2   rb   r;   rR   Z_node_parentrQ   primary_rolestructural_projectZstructural_project_force)rd   Z	sl_reasonr:   Zstruct_projectZstruct_project_forcer*   r*   r+   _HACK24052023_calc_parent  s`    


z!CmfTask._HACK24052023_calc_parentc                 C   sd  | j r| 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	s| jjdkr| jdkr| j
stjj| jddgd| _ | j s| j| _ | jjrN| j rN| jdkrN| jjdkrN| jjdd | jrHtd | jD ]}| j |_ |  q0d | _ | jd	kr`d | _ d S )
N	task.epictask.subprojectztree_parent.parentepicZtree_hidden)r:   sys_typerT   T)rD   u   Скрываем задачу в дереве проекта, её дочерние элементы вставляем вместо неёr   )r   r   r   r:   r   rP   r2   Z	CmfFoldergetr   r   ru   Z
tree_nodesr   rR   r;   )rd   childr*   r*   r+   _calc_tree_parent,  sd    



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r| jjjdkr| jjdkr| j| _| j	jr| jdkrt
ddd	 | j	| _| jjr| jdkrt
d
dd	 | j| _d S )Nr   r   r   r   r
   ztask.subu2   У подзадач нельзя менять EpicTr>   u@   У подзадач нельзя менять Подпроект)r   r   rY   r   rP   r   rC   r   r   r   rR   
subproject)rd   Ztmp_tree_parentr*   r*   r+   r   ^  s,    



zCmfTask._calc_parent_taskc                 C   s&   | j r
d S | jjsd S tj|  d S r   )r   r   r   r2   CmfTimeTrackerZtimetracker_task_change_statusr   r*   r*   r+   _calc_timetrackerz  s
    zCmfTask._calc_timetrackerc                 C   s   | j s*| jjs*| jjs*| jjs*| jjs*d S |   d }| jrD| j}n8| jrbt| jjt	j
rb| j}n| jrp| j}n| jr|| j}|| _d S r   )r   r   r   r:   rC   	main_listZ_load_perm_fieldsr   rY   r2   ZCmfDocumentperm_parent)rd   r   r*   r*   r+   _calc_perm_parent  s,    	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 r1   r   r-   Zto_json.0ir*   r*   r+   
<listcomp>  s     z1CmfTask.get_cache_fields_json.<locals>.<listcomp>rp   c                 S   s   g | ]}| d ddgqS r   r   r  r*   r*   r+   r    s     tags
is_checkedr   activity_id)r"   get_cache_fields_jsonrp   r  r  r   r  )rd   retr(   r*   r+   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   )	rp   r   r   is_not_nullr   rV   rT   r   rz   )rd   r   r   Zw_listr*   r*   r+   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    установлена в соответствии с планом списка)	rp   r   lenr   r   rx   r   rR   r   )rd   r   r   Zself_plan_shiftr*   r*   r+   _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   План сдвинут в соответствии с будильником)	rx   r   r   r   r   daysrY   rR   
_calc_name)rd   Z	date_diffr*   r*   r+   _calc_plan_nolist  s2    

		zCmfTask._calc_plan_nolistc                 C   sb   | j js*| js*| jjs*| jjs*| jjs*dS |  \}}t| j sH| j jrV| || n | 	  dS )u`   
        Ф-я вызывается из базового класса
        :return:
        N)
rp   r   r   rx   r   r   r   r  r  r  r   r*   r*   r+   
_calc_plan  s     zCmfTask._calc_planc                 C   sL  | 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rfd| _tj| ddd	  d S | 
 }| js|jsd| _tj| d|j dd	  d S | jr|jr| jr| jjrd| _tj| ddd	  | j| jj ks| jj| jjkr tj| jkr d| _tj| d	dd	  | j rH| jjrH| jrH| jsHd| _d S )
Nr   Tu~   SimpleLogic: Задача согласована автоматически, т.к. это Непроектная задачаr   r   u   SimpleLogic: Задача согласована автоматически, т.к. согласование отключено в Fu   SimpleLogic: Выполнен сброс согласования, т.к. сменился Постановщик или Проектu   SimpleLogic: Задача согласована автоматически, т.к. постановщик - руководитель.)r   approvedr   r   r:   rY   r   r2   rb   r;   _get_sl_optionssl_task_need_approveZsl_controller_strr   r1   r4   current_personZ
cmf_import
is_defined)rd   
sl_optionsr*   r*   r+   _calc_approved.  sV    



$

"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   zCmfProject:)r   r"   
get_ownersrP   rp   r5   r   r   r   r   r   r:   r   rY   
startswithr#   )rd   r&   r'   Zownerslstownerr(   r*   r+   r  `  s     


zCmfTask.get_ownersc                    s&   | j r
d S | jdkrd S t   d S r
  )waiting_forr   r"   _calc_waiting_forr   r(   r*   r+   r   x  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jdkrd}| jj }|r| js| j jjdkr| jj| _d| _| jjr| jr| jdkrd| _d| _| jdkr| j jjdkrd| _d| _|r8| jjr8| jr8|jr8|jr8tj| j kr8td	dd
 | jr| jjrl| jj| jksd| jjsl| 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jrD| jp*|| _| j jdkrD| j| _| jrPdS d}| jjr| jjsr| 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 j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r@| jp<|| _| js| j|kr|sf|| _d| _|| _tj | d|j! ddd"  | jjs| jjr| j|kr| jr| j| _tj | d| j ddd"  | jdkr|sd| _d| _| jr@| j|kr@| jr@| jr@| j| _tj | d| j d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| j,ggd}|s`| j+-d"g | jd| j+_ | j+"  td# |j.r| -d$d%g | j/| j0krtd& |r|j1rtj|  kr| j2s| jjddd'}|r|| _ | j3jr| j3j| _3td( q| j jjdkrd| _| jdks| jr$d| _d| _dS | j jjdkr| j2rZ| jd| _ td) q| jsl| j4  | j jjdkr| j| j5 kr| j4  | j| _| j| _d| _tj | d*| jj! d+| j j! d,dd"  dS | j jd-kr| j jjd-kr| js|j6rtd.dd
 td/ | j jjdkrP| jp8|| _tj | d0dd"  | j jjdkr| j|kr| jpv|| _tj | d1dd"  | js| j4  | j jjd-kr| j| j5 kr| j4  tj | d2| j j! dd"  dS qqdS )3uS   
            Ф-я вызывается из базового класса
        NimportFr   T	IN_REVIEWZapprove2Zapprove1_reviewu[   Только Владелец проекта может согласовать задачуr>   r  open)status_coder0   )r  IN_PROGRESSZapprove3_notassigneduh   SimpleLogic: Задачу переключили на Постановщика/Руководителя(u   ), т.к. не указан Будильник. Установите будильник, чтобы задача отобразилась у Исполнителяr   r   uM   SimpleLogic: Задачу переключили на Исполнителя(u   ), т.к. указан Будильник.Установите будильник, чтобы задача отобразилась у Исполнителяr   r   c                 S   s   g | ]}|j d kr|qS )r   r   r  r/   r*   r*   r+   r  %  s     
 z1CmfTask._calc_wf_simple_logic.<locals>.<listcomp>rC   rN   r   !=rM   um   Для закрытия задачи необходимо закрыть все дочерние задачиu_   Вы закрыли задачу у которой есть Открытые подзадачиr1   zchild_tasks.cache_status_typeu}   Родительская задача закрыта автоматически т.к. закрыты все дочерниеchecklists_items_countchecklists_items_done_countu_   Внимание! В задаче остались незавершенные чек-листы)r0   u   Спасибо! Статус установлен в "Подтверждение закрытия", для проверки постановщиком или владельцем проектаu   Спасибо! Статус изменен на «Закрыто» т.к установлен флаг «Без подтверждения».uO   SimpleLogic: Задачу переключили на Постановщика(u   ), т.к. статус=''r%  uT   Нельзя брать в работу несогласованную задачу.um   Внимание! Вы взяли задачу без согласования с руководителем.u^   SimpleLogic: waiting_for  установлен т.к. статус снижен в in_progressui   SimpleLogic: waiting_for установлен т.к. статус перешел из open в in_progressu[   SimpleLogic: будильник установлен т.к. статус сменен на )7r   r   r  rv   r   r:   rx   r  osenvironr   r  rY   r   r   r   status_typeapprove_forapprove_for_placeZsl_only_owner_approver  r4   r  r  rR   r   r   r   r-   workflowget_default_statusr2   rb   r   r;   Z,sl_deny_closing_task_before_closing_subtaskshas_child_tasksr   r  r  r
   r   t%   sl_сlose_task_after_closing_subtasksrC   r1   rP   Z.sl_deny_closing_task_before_closing_checklistsr*  r+  Zsl_task_only_owner_closeZ
no_controlstatus_closed_atr}   rz   Zsl_deny_no_approve)	rd   r  Ztask_controllerZis_project_taskZ
need_transZsimple_logicZhas_unclosed_subtasksZ unclosed_subtasks_in_parent_taskZin_review_statusr*   r*   r+   r     s   
 $2


	



 
$








*




zCmfTask._calc_wf_simple_logicc                    sL  t    | jjs,| jjs,| jjs,| js,d S | jjr8d S |  }|j	d krNd 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r
| js|| | _n$| jr| j|| kr|| | _n d S | js6| jtjkr6| jjr6| js6d S | jsH|| | _d S )N)r  i  )r"   _calc_deadliner2  r   r:   rx   r   rr   r  Zsl_deadline_shiftry   r   rz   r{   r|   cmf_created_atager   r4   r  rY   )rd   r  Z
days_shiftshiftrz   r(   r*   r+   r6    sT    



(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 )Nrp   fix_versionsr1   
members.idr   )rP   r2   CmfListr   rp   remover:  )rd   Zsrc_list_idr&   r'   Zsrc_listr*   r*   r+   remove_from_list  s    

zCmfTask.remove_from_listc                 O   s0   |  dg tjj|ddgd}| j| | S )Nrp   r1   r;  r   )rP   r2   r<  r   rp   rw   )rd   Zdst_list_idr&   r'   Zdst_listr*   r*   r+   r     s    zCmfTask.copy_to_listc                 C   s   t j|j| d | S )Nr/   )r2   CmfActiveEntityFilterr   Zadd_active_entity)rd   	filter_idr*   r*   r+   apply_filter  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   TrE   )r2   r@  r   rC  r  r=  r;   )rd   rA  Zactive_entity_filterr*   r*   r+   remove_from_filter  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 )Nrp   rC   zparent_task.nameu   Укажите from_idTr>   u   Укажите to_idu(   Не могу перместить из r   r1   rT   u5   Нельзя переместить задачу в "u/   ", так как она находится в ""u&   Не могу перместить в )rP   rR   r   Zget_cls_by_tuuid_strr2   r<  r>  r@  rD  r
   rC   r1   rY   r   rB  r   r   )rd   Zfrom_idZto_idr&   r'   Zfrom_clsZto_clsZtarget_taskr*   r*   r+   r     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      #№@rH   r   ILIKEaliasz%"z"%r   T)lstripr2   ZCmfTagr   r  rw   )rd   	only_namectxrH  tagr*   r*   r+   _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 rG  )rL  r2   ZCmfLogicTyper   ru   )rd   rM  rN  rH  ltr*   r*   r+   _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 )NrH  F)#   №@rI     
user_localrJ   TrH   r   rJ  %Zloginr)  )r  rL  r  r2   	CmfPersonr   rv   )rd   rM  rN  rH  _filterpersonr*   r*   r+   _process_responsible_token|  s$    

z"CmfTask._process_responsible_tokenc                 C   s0   |  }|  }|d| d| d| fkS )NrS  rT  rU  )lower)rd   stringZhashtagr*   r*   r+   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 )NrH  rS  rT  rU  FTrs   r   r   )ZdayZhourZminutesecondZmicrosecond   )monthsr   )rb  r  )cmfutilZ	RU_MONTHSr   r]  r   r   r   ry   rz   r{   r|   replacemonthr   r   rY   Zyearr   )	rd   rM  rN  rH  Z	month_idxre  r   r9  r   r*   r*   r+   _process_month_token  s>     
zCmfTask._process_month_tokenc                 C   s   |    dS )uG    Ф-я вызывается из базового класса
        N)_calc_from_namer   r*   r*   r+   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r^| j jr^d  fdd| j j D } fd	d| j  D }	t|t|	kr^||	}
t| jD ]}|j |
kr>| j| q>| jd
kr| jr| jr| jjdgd | jr| jjs| j pd | _ n,| j r| j jdsd| j pd | _ n| j sd| _ d S )N z.,;:?!rd   r   .)rT  rS  rU  c                    s"   h | ]}|  r|d d qS r   Nr  r  elZtag_symbolsr*   r+   	<setcomp>  s     
 z*CmfTask._calc_from_name.<locals>.<setcomp>c                    s"   h | ]}|  r|d d qS rj  rk  rl  rn  r*   r+   ro    s     
 r   add_object_typer   1ZEpiczEpic zEpic 1)r   r   r   r  rv   rY   r   r]  striplocalsr   rw   rR  rP  r\  extendr  rstripr   
differencer#   r=  r   r   r:   rP   rp  r  )rd   r   Zname_tokensZundefined_tokenstokenrH  rN  Zdot_token_posZtags_old_nameZ	tags_nameZtags_for_deleterO  r*   rn  r+   rg    sb    



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)ru   r   r   r   ui_view_formui_namer]  r   r*   r*   r+   r     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r~| jr~| j dg | jj| _d S )	Nr:   r   rC   r   zgantt_project.op_gantt_taskrX   r   z main_gantt_project.op_gantt_task)rP   r   rC   r   r:   r   r   r*   r*   r+   _calc_gantt_project$  s    

zCmfTask._calc_gantt_projectc              	   C   s   | j r| j jjdkr*| jdkr*tddd | j r>| j jjdkrX| jsTtj| d | _d S t	
   | js|tj| d }|| _W 5 Q R X d S )Nr   r   r   r   u_   task.epic, task.subproject и task.gantt_project не могут быть без ПроектаTr>   )r:   rY   r   r   rR   rX   r2   CmfGanttTaskZcreate_gantt_taskrc  disable_acl)rd   rX   r*   r*   r+   r   3  s    

zCmfTask._calc_gantt_taskc                 K   s`   | j jr| j| j j| j j | jjs:| jjs:|ddr\| j	D ]}|j
r@| j   dS q@dS )u   
        Изменяем счетчики Оперативной Гант-задачи при изменении задачи
        Zlist_affect_gantt_taskFN)r   r   rX   Ztask_status_is_changed_hookr   r   r   r   r   rp   Zaffect_gantt_taskZtask_plan_dates_is_changed_hook)rd   r'   r  r*   r*   r+   _calc_op_gantt_task_countersH  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
s\t  S | jsl| j sld S t }| jddD ]6}|j|  kr~|jds~|jds~||j q~d	|ksd
|krV| jj s| j
j r| j
r| j
jd| dd | j
j r.| j
jr.| j
j| j
jkr.| js.| j
jd| d d	|krB|d	 d
|krV|d
 d|kr| j
jd| d | jr| j
jd| jj| d |d d|kr| jjr| j
jd| d |d d|kr| j
jd| d |d d|kr| j
jd| d |d d|kr| jj rN| jdkrN| jjdkrN| j
jd| d n*| jjrx| j
jd| d | j
jd| d |d d|kr| j
jd| d |d d|kr| j
jd| d |d d|kr | js | jjr | j
jd| d |d d |krb| j
jd!| d | jj D ]4^}}}|d"kr"|jd#kr"| j
jd|| d q"|d  d$|kr| j
jd%| d |d$ |r| j
jd&| d d S )'Nr   Zsd_apiud   Редактирование запрещено, так как задача в статусе CLOSEDTr>   )r   Zcache_Z_idr:   r8   r.   )r/   Zuse_new_projectzPPP-TSK-MOVEr?  rv   zPPP-TSK-ASSIGNzPPP-TSK-ASSIGNABLE)userr/   r   zPPP-TSK-MODIFY-OWNERrC   rp   r   zPPP-TSK-CLOSEzPPP-TSK-RESOLVEzPPP-TSK-TRANSITION
spectatorszPPP-VW-MANAGErr   zPPP-TSK-DEADLINErx   	executorszPPP-TSK-ASSIGN-EXECUTORSrw   rY  perm_security_levelzPPP-TSK-SET-SECURITYzPPP-TSK-EDIT)!r   r   r   r  Zsl_readonly_closed_taskr4   Z	api_scopeZmark_commentmarkrR   r8   r"   check_edit_permr   r   valuesr   Zproject_perm_allow_fieldsr  endswithr5   r:   r9   r   r   r3   r=  rv   rY   r   rx   r  Z_changes)rd   r  Zchanged_fields_to_checkZfieldZchange_actionZ
change_obj_r(   r*   r+   r  T  s    


&













$











zCmfTask.check_edit_permc                    sT   |  ddddddg | js.| js.| jtjkrP| jrF| jjd| d n
t 	  d S )	Nr   r8   r   rp   rv   r  zPPP-TSK-DELETEr?  )
rP   r   r   r   r4   current_userr8   r9   r"   check_delete_permr   r(   r*   r+   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-полям когда пусто меняется на имя - не создается и не обновляет информацию в созданных нотифаях.
        Поэтому мы сделал этот ХАК с нарушением слоёв.
        Zobj_idrJ   rH   r   rh  Nr)  )
r   r   r   r   r2   Z	CmfNotifyr#   r1   r   r;   )rd   Ztask_notifyr*   r*   r+   _update_empty_task_notify  s    
z!CmfTask._update_empty_task_notifyc                 C   s   | j r| j jjdks| j jr d S d}| jjrZt| jjt| jj D ]}|j	dkrD|}qDqD|sbd S t| j}|D ]D}||kr~qp|j	dkrqp|j
dkrqp|j
dkrtd | j| qpd S )Nr   Flist.agile_sprintr   r%  u\   Внимание! Задача перемещена из Запущенного списка)r:   rY   r   Ztask_allow_multiple_sprintsrp   r   r   r   r   r   r   rR   r=  )rd   Z
add_sprintappended_listZcurrent_sprintsZ
cur_sprintr*   r*   r+   _calc_sprints  s*    




zCmfTask._calc_sprintsc              0      sr   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.d/d0g0}t   | S )1Nr3   zparent.project_typezparent.auto_alarm_datezparent.logic_prefixzparent.activity.prefixz"parent.task_allow_multiple_sprintsrC   parent_task.logic_prefixzparent_task.is_templatezparent_task.listszparent_task.lists.logic_prefixz#parent_task.lists.cache_status_typezparent.sdesk_feedbackproject.default_gantt_task_typer   ztags.tag_categoryzlists.plan_start_datezlists.plan_end_datelists.ordernozlists.perm_has_aclzlists.sys_typelists.logic_prefixzlists.affect_gantt_taskzmain_list.plan_start_datezmain_list.plan_end_datezmain_list.ordernozmain_list.perm_has_aclzactivity.prefixr1  r0  Zcmf_modified_byr   r4  r   r   r   rX   op_gantt_task.actual_start_dater   zcomponents.default_responsiblezcomponents.default_ownerz!scheme_wf.default_task_logic_typez$scheme_wf.default_subtask_logic_typezlists.default_task_logic_typezstatus.need_approver   r:  ru   )r"   rQ   )rd   rT   r(   r*   r+   rQ     sd    5zCmfTask.save_preload_fieldsc                 O   s:   t j| d d| _| jdd t jj| df|| d S )Nr   Zapprove4TrE   Zapprove_started)r2   
CmfApproveZstart_approve_processr1  r;   CmfEventdo_eventr   r*   r*   r+   start_approve9  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)	rP   r   Ztrans_approved	status_tor  r;   r2   r  r  r   r*   r*   r+   _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)	rP   r   Ztrans_rejectedr  r  r;   r2   r  r  r   r*   r*   r+   _approve_rejectedF  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  )rP   r   Ztrans_updatedr  r  r   r*   r*   r+   _approve_updatedN  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_group
resolutionr   r  Zapprover_levelrN   ZmasterZacceptedr(  r[  )r/   r  ZapproverZapprove_typerM   r  TrE   Zapprove_success_one)r   dictr4   r  r2   r  Z_approve_onerP   r  r=  r;   r  r  )rd   r'   r  r  r   Zmaster_filterparamsZapprover*   r*   r+   r   S  s0    




zCmfTask.approve_onec                    s   dt _t j||S )NT)r4   r   r"   create)r%   r&   r'   r(   r*   r+   r  t  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]+).*
        Nrh  r-   INr8   c                 S   s   g | ]
}|j qS r*   r1   )r  r8   r*   r*   r+   r    s     z.CmfTask.find_related_tasks.<locals>.<listcomp>rM   rT   r   )_TASK_CODE_SEARCH_REfindallr2   r
   r#   )r%   r   rT   Zprojectsr   ZcodesZfilter_r*   r*   r+   find_related_tasksz  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r| dg g }| jD ]}|jdkr|| q|D ]}| j| | j| qdS )u   
        При добавлении в список правильно выбирать поле lists или fix_versions
         в зависимости от типа списка
        Nzfix_versions.logic_prefixzlist.releaser  )r   r:  r   rp   rP   r   rw   r=  )rd   r   r/   r*   r*   r+   r     s2    



zCmfTask._calc_fix_versionsc                 C   sz   |  ddg t| j}|| j | jjr:|| jj | jjrP|| jj dd |D }ttj	j
dt|id d S )Nrp   r:  c                 S   s   h | ]}t |jqS r*   )r6   r1   )r  r~   r*   r*   r+   ro    s     z4CmfTask.process_lists_count_cache.<locals>.<setcomp>Zlist_idsr'   )rP   r#   rp   rt  r:  r   r   schedule_deferred_jobr2   r<  Zrecalculate_count_cache)rd   rp   Zids_setr*   r*   r+   process_lists_count_cache  s    
z!CmfTask.process_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"   , попробуйте позже.Tr>   )rp   r   r   r   r   r   r   r   r   r   Zget_lock_keyrR   )rd   r  r*   r*   r+   _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r| j
ddddddd	d
ddddddg | jjr| js| j| jj d| jjj d| jj d}tj| |dd  | jjr| jj| jkr| j| jj d| jjj d| jj d}tj| |dd  |   |   |   |   |   |   |   |   |   | jr| jj rt  |    W 5 Q R X | !  | "  | #  | $  | %  | &  | '  t( j|ddi|}| )  tj*+|  |S | jr| , S | j-js| jr2| | j-kr2t.ddd | j-jr| j-rdddgddd| gd d| j-ggdd| j-gd d| gggg}tj/j0|d!rt.d"dd | jjr| 1  | 2  | 3  | 4  | 5  | 6  | jjr| j7rt8| jj9t8| jj: D ]}|| j7krd | _7q| j7sr| jD ]}|j;d#kr$|| _7 qDq$| j7sr| jD ]}|j;d$krR|| _7 qrqR| jjr| j7r| 
d%g | j7j;d$krt8| jj:t8| jj9 D ]}|j;d#kr|| _7 q֐q| jjs| jr| jr| jjj	dkr| j
ddddddd	d
ddddddg | jjrz| jsz| j| jj d| jjj d| jj d}tj| |dd  | jjr| jj9r| j| jj9kr| jj9j	dkr| jj9j  | jj9j}	|	r|	| jkr| j<|	 d&|	j d| jj9j d}tj| |dd  | jjrl| jj| jkrl| j| jj d| jjj d| jj d}tj| |dd  | jjr| jj9r| j| jj9kr| jj9j	dkr| jj9j  | jj9j}
|
r|
| jkr| j<|
 d'|
j d| jj9j d}tj| |dd  | jjrtj=st8| jj:t8| jj9 D ]0}|j>d(kr.t.d)|j d*| j ddd q.| jst8| jj9t8| jj: D ]0}|j>d(krt.d+|j d*| j ddd q| ?  |@d,sB| jjrB| jArBtBt8d-d.d/}|| jj:}|| jj9}|| }|| }tC||grBtjDjEjF| jGjtB|tB|d0d1 | H  |   |   |   |   | I  | jJjr| jJd2kr| j;d3krt.d4| jJ d5dd | K  | jLjrtjMjN| d6f|| | &  | '  t( j||}|jO|jGkr tPd7|Q  d8tRjS d9tRjT  | j>jrt| j>j:d(krt| jUrt| jV  | jVD ]"}t  |W  W 5 Q R X qP| jXf | | jYjr| jZ[  | j\jr| jZ]  | j-jr| jZ^  | j	r\| jjs| j	r\| jjrt  |    W 5 Q R X n^| jj	r\| jj9	r\| jj9j 	r\|@d:	s\| j_  | j_	r\t  | `  W 5 Q R X | jj	rn| a  | jbd;k	rtjcd|  | j	r| jef  | jdd< | j	s| j	rtjgh|  | j>j	r| j>d(k	r| jji	rtjtjDjk| jGjgd= | jj
s
| jlj
rtjtjmjn | j
o:to| jd>k
p:to| jld>k}|
s`| jj
s`| jlj
s`| jj
rt| 
d?g | p  d@D ]&}tq| |j
rxtjtjrjn  
q
qx| j-
r| j-j; dAk
r| j-j
s| j
rtjtjDjn | j-j9r| j-jr| j-j9j; dAkrtjtjDjn | j;jr*| j;j9dAkr*d>| _s| jtjr\| jr\tu| jjtjvr\| jw| jt | j>jr| j>d(krt  | xtjyjG W 5 Q R X | jzd>dB | j{r| j;dCkrt.dDdd | )  | j|js| j}jrtj~|  tj*+|  |S )ENTr   zdefault_list.plan_start_datezdefault_list.plan_end_datezdefault_list.ordernozdefault_list.perm_has_aclzdefault_list.sys_typezdefault_list.logic_prefixzdefault_list.affect_gantt_taskz%default_list_if_empty.plan_start_datez#default_list_if_empty.plan_end_datezdefault_list_if_empty.ordernoz"default_list_if_empty.perm_has_aclzdefault_list_if_empty.sys_typez"default_list_if_empty.logic_prefixz'default_list_if_empty.affect_gantt_taskuo   SimpleLogic: Задача добавлена в Список для Новых задач без Списка "   " проекта "rF  r   r   ut   SimpleLogic: Задача добавлена в Обязательный список для Новых задач "r   FuK   Нельзя добавлять задачу в eё же подзадачиr>   relation_type.coderJ   system.additional_parentrH   rI   rK   r)  u   Задачи не могут быть родительской и дочерней, так как они связаны связью Дополнительный родитель/Дополнительная дочерняя задача.r  	list.basezmain_list.logic_prefixum   SimpleLogic: Задача удалена из Список для Новых задач без Списка "ut   SimpleLogic: Задача удалена из Обязательного списка для Новых задач "r   uS   Нельзя добавить задачу в Завершенный список "z" - "uU   Нельзя удалить задачу из Завершенного списка "from_sync_subtasks)rp   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   rP   r   r   r5   r1   )rp   Zsprints_idslist_r*   r*   r+   get_correct_sprints  s    	

z)CmfTask.save.<locals>.get_correct_sprints)task_idsprints_to_add_idssprints_to_remove_idsr  )rG   r#   ry  rx  r   u   Вид отображения uk    временно не поддерживается, используйте "task", "list", "post", "gantt"Zspectators_changeduj   DEV: WARNING: У задачи после сохранения совпадает код и id task.values=z, request.url=z, request.data=r  project.servicedeskrE   )r&   r   r:  )r   r:   r  rv   r   r  r   )rq   r}  us   DEV: Недопустимое перемещение простой задачи в структуру дерева)r  r   r   r3   r4   r   r:   r   rY   r   rP   Zdefault_list_if_emptyrp   rw   r2   rb   r;   default_listr   r   r   r   r   r   r   r   r   r   Zneed_approver   rc  r  r  r  r6  r   r   r   r   r   r"   r   CmfBackbonePeerobj_after_save_hookr   rC   rR   r\   r   rg  r  r   r   _calc_estimate_workr   r   r   r   r   r   r=  r   r   r  r   r4  r#   anyr
   _sync_subtask_sprintsZapplyr1   _calc_logic_type_change_guard_calc_agile_story_pointsrz  _calc_structural_listr  r  r  r-   printr  Zrequesturldatarr   Zstaff_control_blocked_personsZcalc_staff_control_blockedr  ru   rX   Ztask_logic_type_is_changed_hookr   Z"task_gantt_project_is_changed_hook task_parent_task_is_changed_hookr  r  r   parent_logic_prefixCmfSDeskSlaTriggertask_changed_hookr7  r}   ZCmfSDeskSlaCycleZupdate_cycle_goalsZsdesk_feedbackr  Zsdesk_send_feedback_requestr:  r<  recalculate_cacher  r  getattrr@  cache_child_tasks_countr  r   r   Zhook_task_tags_changedZ_clear_notifyr  Z_update_opened_notifiesr   rv   r  ra   sync_task_resources)rd   r&   r'   	audit_msginstrZ  Zremoved_listr~   r  Zold_default_list_if_emptyZold_default_listr  Zsprints_newZsprints_oldsprints_to_addsprints_to_removeZself_instancer[  Zis_new_with_listsrf   r(   r*   r+   r;     s   "







	4
4
""



















 &$
,($
zCmfTask.savechangedc                 C   s  | j jsn| jjjsn| jjsn| jjjsn| jjdkr<| jjdksn| jjdkrT| jjdksn|dksn|d k	sn| j	snd 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	r@t| jjD ]Z}|jd
krq|j| jjd| j j| jjj| jjjd	| jd |j| jjd dd|||d qd S | jjrLt| jjD ]n}|jd
krjqV|| jjkrV|j| jjd| j j| jjj| jjjd	| jd |j| jjd dd|||d qVt| 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rn| j j|d< | jjjr| jjj|d< | jjjr| jjj|d< |r
| 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|rf| jD ]N}|jd
ks||
kr4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r"| jjdkr"| 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sD||
krbqD|j| jjd||||	d  |j| jjd d!d|||d qDd S )"Nr   )startedclosedrp   agile_story_pointsop_gantt_task.sched_durationop_gantt_task.sched_workop_gantt_task.actual_workr   r   r%  rw   )estimate_spestimate_durationestimate_workestimate_countr/  zscope-changed)timetracker_history_idtask_operatetask_list_operater  remaining_durationspent_durationr=  r/  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  r/  closer  zstate-change)r  r  r  Zunclose)r  r  r  r  Zreopened)r  r   rX   Zsched_durationrp   
sched_workr   r   r   r   rP   rY   actual_workr   Zhistory_otr_addr1   Zhistory_rte_addrw   r  
time_spentremaining_estimateZend_date)rd   r  	task_listtimetracker_historyr  r  r  r  r  r  Zappendedr  r  r*   r*   r+   r   -	  s>   



	
  

  
  

  






 


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:   rX   rC   rN   r   )r:   r   r   r   rC   rP   rX   r2   r
   r#   r;   )rd   rT   r   rG   r*   r*   r+    _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 )
NrH   rG   rJ   r   TrL   rF   rI   rK   )r2   r~  r#   restorer[   r\   )rd   rZ  
gantt_taskrh   ri   r*   r*   r+   _restore_relations	  s    

&zCmfTask._restore_relationsr@   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 )NTrE   rF   rA   )r   rD   rH   rG   rJ   r   rL   )rA   Zfrom_task_deleterI   rK   )rX   r;   r2   CmfTaskCodeHistoryr#   rZ   r
   r   r~  r[   r\   )
rd   rA   r&   r'   r-   rG   rZ  r  rh   ri   r*   r*   r+   _delete_relations	  s    &zCmfTask._delete_relationsc                 O   s&   | j s
d S | j D ]}|j|| qd S r   )r<   rZ   )rd   r&   r'   	checklistr*   r*   r+   rS   	  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   )rG   rD   r   rA   )r/   rD   )r2   r^   r#   rZ   r_   r`   )rd   rA   r&   r'   rl   r*   r*   r+   _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 )NTr7  )rG   cmf_deletedr   )r/   r  )r2   r^   r#   r  r_   r`   )rd   r&   r'   rl   r*   r*   r+   _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
s| jrttjj |   |   | jr| jj dkrttjj | jr| j|  tj|  |S )Nr   r8   r   sdesk_sla_cyclesr   rC   rp   r:  rv   r  r<   r   )rP   r  rZ   _delete_task_resourcesr  _delete_timetracker_history_delete_subtasksr  rS   r"   rp   r:  r  r2   r<  r  r  #_update_additional_parent_relationsrC   r   r   r
   child_task_deleter  Zobj_after_delete_hook)rd   r&   r'   Zsdesk_sla_cyclerm   r(   r*   r+   rZ   	  s8         
zCmfTask.deletec                    s>  t  j||}| dddg |   |ddsB|   |   |   |   |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 )NrX   rC   r  	recursiveFr:   r   TrE   parent_task.has_child_taskszparent_task.parent_task)r"   r  rP   r  r   _restore_timetracker_history_restore_task_resourcesr  r  r   _restore_epics_subtasks_restore_subtasksr4  r;   rC   rQ   _calc_cache_branch_gantt_path_recalc_gantt_path)rd   r&   r'   rm   r:   r(   r*   r+   r  $
  s<    

zCmfTask.restorec                 O   s>   | dd}d|d< tjj| |d}|D ]}|j|| q(d S )NrA   Fr  r   rD   )r   r2   r]   r#   rZ   )rd   r&   r'   rA   rj   rk   r*   r*   r+   r  [
  s
    z#CmfTask._delete_timetracker_historyc                 C   s&   t jj| dd}|D ]}|  qd S )NTr  )r2   r]   r#   r  )rd   rj   rk   r*   r*   r+   r  c
  s    z$CmfTask._restore_timetracker_historyc                 O   s\   | dd}tjj| |d}|D ]"}tjj|j|dr |j|| q tj| ddd  d S )NrA   Fr   rD   )r1   rD   !   Подзадачи удаленыr   r   )	r   r2   r
   r#   r   r1   rZ   rb   r;   rd   r&   r'   rA   
tasks_listrG   r*   r*   r+   _delete_epics_subtasksh
  s    zCmfTask._delete_epics_subtasksc                 O   s>   t jj| dd}|D ]}|j|| qt j| ddd  d S )NTr  -   Подзадачи восстановленыr   r   r2   r
   r#   r  rb   r;   rd   r&   r'   r  rG   r*   r*   r+   r  v
  s    zCmfTask._restore_epics_subtasksc                 O   sL   | dd}tjj| ||d}|D ]}|j|| q"tj| ddd  d S )NrA   FrB   r  r   r   )r   r2   r
   r#   rZ   rb   r;   r  r*   r*   r+   r  
  s    zCmfTask._delete_subtasksc                 O   s>   t jj| dd}|D ]}|j|| qt j| ddd  d S )NT)rC   rD   r	  r   r   r
  r  r*   r*   r+   r   
  s    zCmfTask._restore_subtasksc                 O   s<   | dd}tjjdd| g|d}|D ]}|j|| q&d S )NrA   Fr:   rJ   rL   )r   r2   ra   r#   rZ   )rd   r&   r'   rA   assignments
assignmentr*   r*   r+   r  
  s    zCmfTask._delete_task_resourcesc                 O   s0   t jjdd| gdd}|D ]}|j|| qd S )Nr:   rJ   TrL   )r2   ra   r#   r  )rd   r&   r'   r  r  r*   r*   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  rJ   r  rI   zin_link.op_gantt_taskr   )r2   r\   r#   rK   rX   Z*additional_children_relations_changed_hook)rd   Z!additional_parent_tasks_relationsrelationZadditional_parent_gantt_taskr*   r*   r+   r  
  s    z+CmfTask._update_additional_parent_relationsc                    s   |  ddg |jdkr8|js8tjs8| j  tjj| _	| j
sV| jsV|jsV| 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  r   TrE   r  )rn   rn   )rP   r   r3   r4   r   cmf_modified_atr}   r  r1   Zcmf_modified_by_idr   Zis_recursion_saver;   r  Zprivater2   r  r  r  r  r"   _comment_save_hook)rd   rn   r&   r'   r(   r*   r+   r  
  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   rJ   Zperm_encryptr(  Tr)  r  c                 S   s   g | ]
}|j qS r*   r  )r  cr*   r*   r+   r  
  s     z/CmfTask.clean_after_encrypt.<locals>.<listcomp>)r2   rb   r#   r1   rZ   rc   )rd   r&   r'   Zcommentsrn   Zattachmentsro   r*   r*   r+   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   r(  r   r   r  r  r  z
list.boardrH   r   ZtrashrJ   r   rN   r:   object_fieldsrM   rT   r   )r   rw   r"   field_options_list)	r%   relation_field_namer  rM   rT   r   Zfilter_by_projectr'   r   r(   r*   r+   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   rN   rH   r   r  r  r  )r   r  r%   r  r  rM   rT   r   r'   r*   r*   r+   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   rN   searchrH   r   r   r   )r  rM   rT   r   slicer   r   r(  r  )r   r"   r  r  )r%   r  r  rM   rT   r   r  r'   ZepicsZend_cntZ	not_epicsr(   r*   r+   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 )NrH   Z
cmf_hiddenrN   Fr   r  r   rJ  rX  r   rK  r  )r   r2   ZCmfComponentr#   r%   r  r  rM   rT   r   r'   r  r*   r*   r+   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   rN   r   r  r   TZinclude_hiddenr  r   r"   r  r  r(   r*   r+   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   logic_type_idrN   r  r  r  r(   r*   r+   request_type_option_list4  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 )	Nrp   r  )r:  affected_versionsr   rC   r   r   request_type)	r  Zreleases_options_listr  r  r  r  r!  r"   r  r  r(   r*   r+   r  <  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   )r-   rT   r   zAuto task reopenu'   Переоткрываем задачу)r:   r   NZdefault_projectr   zNew auto task for r   z
) project 
rh  )r-   r   r   rv   r   rq   r:   r   )r  hashlibZmd5encodeZ	hexdigestr2   r
   r   r   r2  r3  r   rx   r}   rb   r;   rY  rV   rT   r   Zget_obj_by_tuuid_strr   r-   r1   rY   )r   r   Z
extra_textrq   responsible_idZcmf_owner_idr   _kwargsZtask_keyZ	task_hashZ	task_coderG   rv   r   r:   r*   r*   r+   	auto_taskU  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 )	NrW  rJ   Tr)  r   r%  r)  )Zin_progressr   )
r2   rY  r#   r1   r  r
   r,   r   r!   rY   )r%   rM   r&   r'   ZpersonsZin_progress_filterZcount_filterr[  resultZin_progress_countr   r*   r*   r+   get_responsibles_tasks_count  s    

z$CmfTask.get_responsibles_tasks_countc                 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 | jjrN| jrNd S | j	
| | _d S r   )r   r   r:   r   r2  r   rp   ru   r   	scheme_wfcalc_workflowr   r*   r*   r+   r     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   Нельзя изменить Логический тип задачи на Гант-проектTr>   uT   Нельзя изменить Логический тип у Гант-проекта)ru   r   r   r   rR   r   r*   r*   r+   r    s    z%CmfTask._calc_logic_type_change_guardc                 C   sP   | j js8| jjr&| jdks8| jjdks8| jjr4| js8d S |   | | j  d S )Nr}  r   )	rC   r   ru   r   r   r   r4  r  r  r   r*   r*   r+   r     s    
	zCmfTask._calc_gantt_pathr   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 > 100Tr>   r   r   r   r   r   r   cache_branch_gantt_pathrC   r4  r:   rC   rT   FrE   r   )rC   r_count)rR   rP   r   r   r   r2   r
   r#   r4  r  r1  r   r   r;   r  _check_relations)rd   rC   r3  ZchZ	need_saver*   r*   r+   r    sZ    

   


zCmfTask._recalc_gantt_pathc                 C   s   | j   | js,| j dkr,d | _|   d S |sD| ddg | j}|sRg | _d S |jj}|d krnt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j ddd | | j d S )Nr}  #parent_task.cache_branch_gantt_pathr  zODEV: WARNING: _calc_cache_branch_gantt_path: if cache_branch_gantt_path is NoneTr>   )r1   r-   r   r   c                 S   s   g | ]}|d  qS r  r*   r  tr*   r*   r+   r    s     z9CmfTask._calc_cache_branch_gantt_path.<locals>.<listcomp>ul   Произошло зацикливание! Попытка добавить дочернюю задачу "uK   ", которая уже является родительской для "rF  )r   r   r4  r1  r4  rP   rC   rY   rR   r1   r-   r   )rd   rC   r1  r*   r*   r+   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 )Nr5  c                 S   s   h | ]}|d  qS r  r*   r6  r*   r*   r+   ro    s     z+CmfTask._check_relations.<locals>.<setcomp>c                 S   s   h | ]}|d  qS r  r*   r6  r*   r*   r+   ro    s     z&cmf_task._check_relations, task_code: z, parent_tasks: r  r  zsystem.finish:startzsystem.finish:finishrH   rK   rJ   rI   r   u   Невозможно перенести задачу из-за того, что существует связь ОН/ОО у задачи "z" u?   . Удалите связь и попробуйте снова.Tr>   r  z,out_link.parent_task.cache_branch_gantt_pathz out_link.cache_branch_gantt_pathzout_link.has_child_tasksrT   rM   )
gantt_path)r   rP   rC   r1  r4  r5   r1   rY   r4   r   r-   r2   r\   r#   rI   rK   rR   r   _check_additional_relations)rd   rC   r9  rZ  _fieldsri   rG   Zadditional_child_filterZadditional_child_fieldsZadditonal_child_relationZadditional_childr*   r*   r+   r4    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 )Nr0  u_   DEV: Защита от рекурсии: cmf_task._check_additional_relations: if r_count > 100Tr>   )rC   r9  r5  r1  r4  r2  r   )r9  r3  )rR   r   r4  rC   r2   r
   r#   r4  r:  r1   rY   )rd   r9  r3  Zchild_fieldsr   r*   r*   r+   r:  ;  s    z#CmfTask._check_additional_relationsc                 C   sP   |  dg tjjdd| jgdd|jggd}|sLd| _|   | jdd	 d
S )u   
        Убирает метку дерева у родительской задачи при удалении или перемещении дочерних задач
        r4  rC   rN   r1   r(  r)  FTrE   N)rP   r2   r
   r   r1   r4  r  r;   )rd   r   Zhave_childrenr*   r*   r+   r  O  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_taskTrE   )rC   r   r  rP   r4  r  r;   rX   Z$task_has_child_tasks_is_changed_hookr   r  r   r*   r*   r+   r   Z  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 }| ddg | j r0| j jr0| j jj	r0| j jj	}| j jj
}|r|ddddddg | j| d	|j d
}tj| |dd  nt|jr0| j|kr0|j| jkr0|jddddddg | j|j d|jj d|j d}tj| |dd  | j jr| js| j j}|ddg |jr|jj	r|jj	}|jj
}|r||kr| j| d|j d}tj| |dd  n\|jr| j|kr|j| jkr| j|j d|jj d|j d}tj| |dd  d S )Nr   z0responsible.primary_role.structural_project_listr   r   ZordernoZperm_has_aclr   r   uU   SimpleLogic: Задача добавлена в структурный список "uG   " т.к. он указан в должности исполнителяr   r   u>   SimpleLogic: Задача добавлена в список "r  u   " т.к. он является Структурным проектом Главной роли ответственного по задачеz,primary_role.structural_project.default_listz$primary_role.structural_project_listuS   SimpleLogic: Задача убрана из структурного списка "uX   " т.к. он указан в должности прошлого исполнителяu<   SimpleLogic: Задача удалена из списка "u   " т.к. он является Структурным проектом Главной роли прошлого ответственного по задаче)rv   r   r   r   rt   rp   r   rP   r   r   Zstructural_project_listrw   r   r2   rb   r;   r  r:   r   r=  )rd   Zappend_structural_project_listr   r  Zold_responsibleZremove_structural_project_listr*   r*   r+   r  l  sd    

zCmfTask._calc_structural_listc                 C   sl   | j s| jjs| jjd ksd S | jrht| jjtjrh| dg | jjd krh| jj	jd k	rh| jj	| _d S d S )Nz!parent.default_agile_story_points)
r   r:   r   r  rY   r   r2   r   rP   Zdefault_agile_story_pointsr   r*   r*   r+   r    s    
z CmfTask._calc_agile_story_pointsc                 C   s   | j jsd S | jr8| jj  | 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 )Nu   DEV: FATAL: нельзя изменять поле estimate_work, когда существует базовый Гант-планTr>   r  
const_work)r  r   Zbp_gantt_taskr  r   rR   rX   rP   r   r<  r;   r   r*   r*   r+   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|d| j d| j d	d

  |jjS )u    Создание задачи из шаблона
        :param self: Шаблон документа
        :param params: Параметры для шаблона
        :return: Идентификатор новой задачи
        tmplt_document.textrp   r   r   z%d.%m.%YTrE   u0   Задача создана из шаблона r   r   )rP   create_from_templatery   rz   r   strftimerp   r:   r   r   r;   r2   rb   r-   r1   rY   )rd   r  new_taskZnow_dater*   r*   r+   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)rP   r   r"   +get_default_mail_notification_template_namer   r(   r*   r+   rA    s    
z3CmfTask.get_default_mail_notification_template_namec                    sp   |  | j tj| jjpd|d< | jr4| jjjp6d|d< |d  dd	dd | j
D  7  < t jf |S )Nrh  Zobj_result_textZobj_responsible_namesr   c                 S   s   g | ]}t |jpd qS )rh  )r6   r   )r  rr*   r*   r+   r    s     z-CmfTask.full_search_index.<locals>.<listcomp>)rP   Zfull_search_fieldsr2   ZCmfFullSearchZ
strip_htmlresult_textrY   rv   r   joinr  r"   full_search_indexrd   r'   r(   r*   r+   rE    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  )
r4   r  r   r6   r2   rY  r   r   Ztimetracker_task_change_timer   )rd   r  r  r   dater   r  r*   r*   r+   r     s    

  zCmfTask.timetracker_change_time   )	only_oncer$  rq   c                 K   s   t j|  d S r   )r2   r
   _recalculate_codes)r   r*  r*   r*   r+   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      r8   rN   r-   T)rM   rT   r  rD   r   )from_recalculaterE   )r2   r
   r#   r8   
_calc_coder;   Zcommit_with_event)r   r  limitZ
task_slicerG   r*   r*   r+   rK    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   Удаляем историю выдачи кодов задачам из проекта r-   )r8   rT   u   Всего задач: c                 S   s   z
t | W S    Y dS X d S )Nr   )r   )r  r*   r*   r+   tryint<  s    
z:CmfTask.reindex_project_tasks_code_numbers.<locals>.tryintc                    s    | j jdd S )Nr   r   )r-   rY   
rpartition)r7  rQ  r*   r+   <lambda>C      z<CmfTask.reindex_project_tasks_code_numbers.<locals>.<lambda>)r   r   r   u'   Обрабатываем задачу: )rG   r   rN   TrL   u   Код u    занятrE   )rc  Zdisable_notifyr2   r   r   r  r
   r#   r  sortedr  rZ   r-   rY   rR  r   r;   )r   Zwith_history_deleter8   r  r  rG   ZhistZnew_coder*   rS  r+   "reindex_project_tasks_code_numbers*  s0    	
z*CmfTask.reindex_project_tasks_code_numbers<   )rJ  Zsoft_time_limitr$  rq   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   rT   r   rC   rN   r)  zUpdate cache_members_count z -> r   TrE   )Znode_idZelements_countztree-node-count-changes-ztree-node-count-changesr0  zRecalculate r%  z lists caches)r2   r
   r#   r   r  r4   r   r1   r;   rY   Zcmf_emit_event
cmf_commit)r*  r%   Ztotal_countZ
calc_countZcmf_epicZ
real_countZ
event_datar*   r*   r+   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   rC   r   rZ  r[  )r   rP   rC   unionget_all_followersr"   )rd   r[  r&   r'   rm   r(   r*   r+   r]  r  s    
   zCmfTask.get_all_followersinline_save)tmp_objcreate_formui_form_moderT   c                   s~   | j |ddddddddd	g	d
d|}|jrZ|jjdkrZd}t j|||||d|S |pb|j}t j||||d|S )Nru   r   zproject.ui_form_schemezproject.cust_field_conf_schemezproject.logic_prefixr  r3   r#  ,request_type.ui_form_view_inner.ui_form_jsonT)rT   rD   r  r^  )r_  ra  r`  rT   )ra  r`  rT   )r   r8   r   r"   r   r3   )r%   r_  r`  ra  rT   r&   r'   r(   r*   r+   r   z  s"       
zCmfTask.ui_getc                    s<   t  |}t|dd r8tjj|jjd}tj||_|S )NrX   r  )r"   get_automation_ui_formr  r2   r~  r   rX   r1   )r%   r/   ui_formrX   r(   r*   r+   rc    s
    zCmfTask.get_automation_ui_form)
ui_form_idr  c                 C   s   t j|S r   )r2   	CmfUiFormZget_ui_group_fields)r%   re  r*   r*   r+   _get_ui_group_fields  s    zCmfTask._get_ui_group_fieldsc                    sv   t t|j}|p|j}|r`|jdkr`|r2|}n| j|jddgd}|r`|jr`|jj	r`|jj	}t
 j|||||dS )Nr  r#  rb  rE  )tmp_is_public_formtmp_ui_view_formr`  rd  )r   Zget_cache_projectr6   r   r3   r   r   r1   r#  Zui_form_view_innerr"   _build_ui_form)r%   r_  rh  ri  r`  rd  Ztmp_projectr/   r(   r*   r+   rj    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)r-   rT   cache_inmemory)r2   rf  r   r   r*   r*   r+   _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   rn  ro  rp  rq  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dg t j|
||d|}| j	s|j
jdd|_d |_tjjddd}|r\dd|gg}tjj|dd| gg dgdD ]}| }||_|  qtjj|dd| gg dgdD ]}| }||_|  q>| j	sxtj| ||d  | jjr| jjr| jj}n| jj}|jpd|j |_| || |r||_d |_	|	rd!d" |jD |_ng |_d|_|  |rLtjjd#d| gdd$}|D ],}|j|j jd% |||||||d& d' q|d(kr`|j!"  tj#$| | j%r~| &| |S ))N)r  r   rn  ro  rp  rq  new_parent_idr  zcopy_task: task_id: z	, level: T**zattachments.urlr  rp   r  r  zattachments.url_previewzattachments.url_preview_imgr  r2  r=  ztmplt_document.text_renderr<   )r   rn  r  r  zsystem.clone)r-   rl  relation_typer(  rI   rJ   r   rK   )rI   rK   rx  rh  Fc                 S   s   g | ]}|j d kr|qS )r  r&  r'  r*   r*   r+   r    s     
 z CmfTask.copy.<locals>.<listcomp>rC   )rM   Zinclude_templatesu    Копияr   )r   Zcopy_attachmentro  rp  rq  rr  rs  rt  r   )'r1   rY   r  copy_task_with_subtasksr4   r   rP   r"   r   r   r2  r3  r   r  r2   ZCmfRelationTyper   r\   r#   clonerI   r;   rK   tmplt_documentr  Ztext_renderr   _clone_op_gantt_taskrC   rp   r   r
   r   rX   Ztask_copy_hookra   r  r<   _copy_checklists)rd   r   rn  ro  rp  rq  rr  rs  rt  ru  r&   r'   rv  new_objZ
clone_typerZ  r  Znew_relationZ
tmplt_textZsubtasksre   r(   r*   r+   r     s         










zCmfTask.copyc                 C   s   | j D ]}|j|d qd S )NrO   )r<   r   )rd   r:   r  r*   r*   r+   r}    s    
zCmfTask._copy_checklistsr  u!   Копирование задач)rJ  Zonly_once_argsdescriptionZshow_bg_progressbarc           	   	   C   sL   t jjdd| gd}||  t jj|d}|j||||||dd d S )Nr1   rJ   r)  r  T)r   rn  ro  rp  rq  rs  rr  )r2   r
   r   rP   rQ   r   )	r  r   rn  ro  rp  rq  rv  rG   rs  r*   r*   r+   ry    s    
   zCmfTask.copy_task_with_subtasksc                 C   s   |j dg |j  |_ d|j _d|j _d|j _d|j _d |j _d |j _t	d|j _
t	d|j _||j _|rv||j _|j jdd d S )Nrw  r   z0.00TrE   )rX   rP   rz  r  Zactual_durationZactual_completeZactual_myself_workZactual_start_dateZactual_finish_dater   Zactual_costZactual_myself_costrG   rC   r;   )rd   r~  rs  r*   r*   r+   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/r%  )rP   r   r{  r-   r"   hrefr   r(   r*   r+   r  5  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  --r1   zlists.idr   )rM   rT   r  )r   r   r,   rp   r1   r  )	r%   rM   r*  r,  ZpageZ	page_sizer  rG   r  r*   r*   r+   r   =  s      

zCmfTask.count_tasks_by_listsc                 C   s|   | j s| jS | dddg | jddg | jr>| jj  | jrr| jjrr| jrr| jjrr| jjj	d | jjj	 S | jjj	S )Nzproject.task_code_prefix'project.task_code_use_logic_type_prefixzlogic_type.obj_code_prefixtask_code_use_logic_type_prefixtask_code_prefixr   )
r   Zcode_prefixrP   r8   ru   Zobj_code_prefixr   r  r  rY   r   r*   r*   r+   get_code_prefixM  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'  r-   rN   TrL   r   u8   Превышен лимит поиска кода limit=z model=uA   , возможно надо отключить def gen_code: passz$!!! --- gen_code::duration too long z.1fz sec, r   z, r   )r"   gen_codetimer2   r  r   AssertionErrorr   r  r1   rT   r-   )rd   r-   r  startrP  r  Zdurationr(   r*   r+   r  i  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r\| j}| jjrt| jjrt| 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rj| j j	|   dsj| j j	}| jsV|rVtjj|dsVtj|| |d}|  d | _ t   d S | jjr| dg | jr| j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   )r-   )r-   rG   r8   Tr  )r-   r8   r   ru   r"   rO  r  r   r  rY   r   r2   r  r   r;   r   rP   r  r   )rd   rN  r8   Zproject_old
new_prefixZ	prev_codeZcode_historyr(   r*   r+   rO  {  sn    
,
$


zCmfTask._calc_coder8  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 )Nr8  T)ZTEXKOM_skip_failread_audit)r#   Z_acl_check_readrw   ZCmfPermissionError)r%   rT   rM   r&   r'   Zres_uncheckedrm   rB  r*   r*   r+   r     s    zCmfTask.public_listc                    s   d|d< d|d< t  jf |S )NFZwith_parent_ownerZinherit_executors)r"   r   rF  r(   r*   r+   r     s    zCmfTask.all_relation_personsc                 C   s<   | j j  | j jj}| | jj|  | | jj| d S r   )rX   r  r   rY   #_update_actual_work_for_all_parentsrC   r   r   )rd   actual_work_timer*   r*   r+   _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)rX   r   r  r;   )rd   rG   r  r*   r*   r+   r    s    
z+CmfTask._update_actual_work_for_all_parentsz@hourly)rJ  r$  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 ]^}|j	r|
 }t d|  |jjr|jj|_|jjdd|_|j  |j|_d |_d |_|  |  |jd
d qtt d|  |jdkr|jjdkrP|jj}|  |jr|j|jkr||_q|jjrd|jj|_|jr~|jjdd|_|jjdd|_|  qt|jjd krt|jjdd|_|jjdk r|j  |  qtd S )!Nz(Run CmfPerson.cron_celery_check_periodicrH   zstatus.coder(  r#  r   r%  period_create_newrN   Tperiod_intervalperiod_next_datez<=rs   r  r   r2  period_clear_checkboxr   r=  rr   rx   r   z6CmfPerson.cron_celery_check_periodic: create new task )r$  rE   z2CmfPerson.cron_celery_check_periodic: reopen task )r   r"  r   ztox-checklist--checkedrh  pause)r4   r   ry   rz   r{   r|   r2   r
   r#   r  r>  r{  r  r   r2  r3  r   rx   r}   rr   r  r  r;   Z_cacl_next_periodr   r8  rY   r  rd  r-   )rZ  rG   r@  Zold_deadliner*   r*   r+   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  rC   r   rX   r  r  r"   _save_importr   r(   r*   r+   r  ?  s    
zCmfTask._save_importc                    sB   t  |}|s>|t  dddg |tjdddg7 }|S )NZ
cmf_authorr7  r5  rx  rK   rI   )r"   import_shop_fieldsrt  r2   r\   )r%   Zfields_namerm   r(   r*   r+   r  L  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 )?Nr1   r-   r   r   rC  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.loginz	tags.namez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  rq   rC   r7  r  r   r   r   r  r  r5  r  r  rr   r  r   r:  r"  zop_gantt_task.actual_costzop_gantt_task.actual_completez#op_gantt_task.duration_is_estimatedrx   r  Zcf_)r2   r
   rT   keysr  rw   r"   export2file)r%   rT   ZbqlZformat_fileZinclude_archivedrf   r(   r*   r+   r  \  sz                                         
zCmfTask.export2file)id_listrT   c                 C   s\   g }| j dd|gdgdD ]}||jj|dj q|rX|| jdd |D |d |S )Nr1   r  r  r   r   c                 S   s   g | ]
}|j qS r*   r  r'  r*   r*   r+   r    s     z8CmfTask.group_changes_list_recursive.<locals>.<listcomp>)r#   rt  r   r   rY   r   )r%   r  rT   ZchildrenrG   r*   r*   r+   r   z  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  r8   r:   ru   r   Zrequired_fieldsZ	ui_fieldsrequired)rj  r  r   r   )r%   r  subgroupr_  rk  rf   metar*   r*   r+   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  r.  r2  )Zworkflow_idZstatus_list)r2   ZCmfSchemeWfZcalc_schemer/  ZCmfWorkflowZget_status_listr1   rY   )r%   r  r  r_  r*   r*   r+   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  rC  r   rY   )rd   r  r*   r*   r+   r     s    zCmfTask._clean_result_textc                 C   sJ   | j rF| jsF| jrF| jj}|D ]&}|jdks|jdkr8q| j| qdS )ux   Устанавливаем для dummy task теже спринты, что и у родительской задачиr  r   N)r   rp   rC   r   r   rw   )rd   Zparent_task_listsZparent_listr*   r*   r+   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
        rp   r   r1   r  r)  z)deferred_job(_sync_subtask_sprints) task:r4  r3   rC   r   r(  r   r8  r   zjob FAIL RESURSION r   FT)r  r  N)r2   r
   r   r<  r#   r   logginginfor1   errorr5   rp   rw   r=  r;   rY  r4  )r  r  r  rG   r  r  Zprocessed_task_idsZprev_lvl_task_listZnew_lvl_task_listZsub_tasks_listr  Zsub_taskr  Z	sprint_idr*   r*   r+   r    sN    



zCmfTask._sync_subtask_sprintsc                 C   s   | j r| j js| jr| jrdS tjjdddd| j jggdgd}|sHdS |D ]6}tjjdd	d| j	gd
d|ggdrtqLtj
||  qLdS )u:   Создание чек-листов из шаблоновNZdefault_for_logic_typesZEXISTSr-   rN   r   r   ZANDr:   Zfrom_templater)  )ru   r   r   r3   r2   ZCmfChecklistTemplater#   r-   ZCmfChecklistr1   Zcreate_checklist)rd   Z	templatestemplater*   r*   r+   r     s    "zCmfTask._calc_checklistsc                 O   s   |  dg dt| jiS )Nr  Zapprovers_count)rP   r  r  r   r*   r*   r+   r     s    zCmfTask.count_approvers)NN)F)F)F)F)NNN)r  NN)N)NNNNN)NNNN)NNNNN)NNNN)NNNN)NNNN)NNNN)NNNNNN)N)r   )N)NN)Nr   )rG  NN)F)FNFN)N)F)N)NNr  F)N)__name__
__module____qualname__modulesrG   rT   cmf_taskr
   Zapi_methodsservicedeskr2   CmfTaskMixinclassmethodr#   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  r  r  r   r   r6  r>  r   rB  rD  r   rP  rR  r\  r_  rf  r  rg  r   r|  r   r  r  r  r  r  rQ   r  r  r  r  r   r  recompileASCIIr  r  r   r  r  r;   r   r  r  r  rS   r  r  rZ   r  r  r  r  r  r  r   r  r  r  r  r   r  r  r  r  r  r!  r  staticmethodZcmf_deferred_jobr+  r-  r   r  r   r  r  r4  r:  r  r   r  r  r  r   rA  rE  r   rL  rK  rW  r  r   r]  r   rc  r6   rg  rj  rm  boolr   r}  ry  r|  propertyr  r   r  r  rO  r   r   r  r  r  r  r  r  r   r  r   r   r   r   r  r   r   __classcell__r*   r*   r(   r+   r
      s  
@!&<
%$A2
	A2  *K
 
+  *Hw8!	  l 	&7                                               +0 )=
,	, "		      dKK	9r
   )ry   r  collectionsr   r   decimalr   r'  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	   r  r2   r  r  rG   rT   r
   r*   r*   r*   r+   <module>   s   