B
    f                @   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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d&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Z fd0d1Z fd2d3Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Zd>d? Z d@dA Z! fdBdCZ"dDdE Z#dFdG Z$dHdI Z%dJdK Z&dLdM Z' fdNdOZ( fdPdQZ)dRdS Z* fdTdUZ+dVdW Z,dXdY Z-dZd[ Z.d\d] Z/dQd^d_Z0dRdadbZ1dSdcddZ2dTdedfZ3dgdhdidjdkdldmdndodpdqdrdsZ4dtdu Z5dUdvdwZ6dxdy Z7dVdzd{Z8d|d} Z9d~d Z:dd Z;dd Z< fddZ= fddZ>dd Z?dd Z@ fddZAdd ZBdd ZCdd ZDdd ZEdd ZFe fddZGeHIdeHjJZKedWddZLdd ZMdd ZN fddZOdXddZPdd ZQd`dddZRd`dddZSdd ZT fddZU fddZVdd ZWdd ZXdd ZYdd ZZdd Z[dd Z\dd Z]dd Z^dY fddĄ	Z_edZ fddƄ	Z`ed[ fddȄ	Zaed\ddʄZbed] fdd̄	Zced^dd΄Zded_ fddЄ	Zeed` fdd҄	ZfegehddԍdaddքZiegdbdd؄Zjddڄ Zkdd܄ Zlddބ ZmdcddZnddddZodeddZpdd Zqdd Zrdd Zsdd Ztdd Zudd Zv fddZw fddZxdfddZyegehdddddd Zzegdd Z{egdgdd Z|egehdӐdddddd Z}dߐde~d fddZedd`d	dd
 fdd
Zedh fdd	Zedd Zd`d`d`d`d`ddߐdeeeeed fddZegehdӐdgddӐddd Zdd Ze fddZediddZd d! Z fd"d#Zdj fd$d%	Zeddd&d'd(Z fd)d*Zd+d, Zd-d. ZegehddӐd/d0d1d2 Z fd3d4Zedk fd5d6	Zedled fd8d9Zedmeed:d;d<Zeeed=d>d?Zeeed=d@dAZeeedBdCdDZdEdF ZegehdGdӐdHeeedIdJdKZdLdM ZegeheeeddNdOdPZ  ZS (n  CmfTaskall_relation_personsapprove_onecopycopy_to_listcountcount_tasks_by_listscreate_dummy_taskcreate_task_from_templatedelete_dummy_taskgroup_changes_required_fieldsgroup_changes_list_recursivegroup_changes_statusesgroup_changesZmark_clickedmovesave_dummy_taskZstatus_options_listtimetracker_change_timeui_getpublic_listZ
public_getN)include_systemc               s   |s| dd t j||S )NsystemF)
setdefaultsuperlist)clsr   argskwargs)	__class__ !./modules/task/models/cmf_task.pyr!   0   s    zCmfTask.listc               s   |s| dd t j||S )Nr   F)r   r    r   )r"   r   r#   r$   )r%   r&   r'   r   6   s    zCmfTask.countc               s   |s| dd t j||S )Nr   F)r   r    slist)r"   r   r#   r$   )r%   r&   r'   r(   <   s    zCmfTask.slistc             O   st   t jf ddi|}|j|_d|_|jdd |jrZ|jjd|ddsZd |_d |_|  |	  |
  d|jiS )	NcodeZdummyT)Zskip_project_perms_checkzPPP-TSK-CREATEF)objraise_errorid)modelsr
   r,   r)   is_dummy_calc_projectprojectcheck_project_role_accessparentZ_calc_default_fieldsave)r"   r#   r$   Z
dummy_taskr&   r&   r'   r   C   s    zCmfTask.create_dummy_taskc       
      C   s  |  |  dg  | js.td| j dd x(tjj| dddD ]}d |_|	  qBW x.| j
D ]$}t| j
| tj
jr`t| |g  q`W | j	dd | jr| jj}d | _| j	dd |j| x$tjj| ddD ]}|j| qW x8tjjdd	d
| gdd
| ggddD ]}|j| q
W tjj| dd}x|D ]}|j| q6W x<tjtjfD ],}x$|j| ddD ]}	|	j|	 qnW qZW x,tjjdd| gddD ]}	|	j|	 qW | j|  d S )Nr.   u   Не dummy task T)abort)parent_taskinclude_deletedr   )	only_data)taskr6   ORout_linkz==in_link)filterr6   )r2   r6   r*   =)load_fieldssave_preload_fieldsr.   	cmf_alertr,   r-   r
   r!   r5   r3   fields
issubclasscmfZ
CmfM2MBasesetattrop_gantt_taskvaluedpdeleteCmfShadowLinkCmfRelationOptionCmfTimeTrackerHistoryCmfListHistoryOTRCmfListHistoryRTECmfStatusHistory)
selfsubtask
field_namegtlinkreltt_history_listtthZmodelhr&   r&   r'   r   _   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rx&| jjD ]}|| jkr| j| qW | 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)tz)r>   Zcloned_fromr2   
logic_typerY   responsiblerX   appendrZ   
alarm_datedatetimenowtimezoneutcset_now)rO   lZdeadline_minr&   r&   r'   #_save_dummy_task_sync_from_template   s,    





"z+CmfTask._save_dummy_task_sync_from_templatec             C   s   |    | js"td| j dd x:| D ].\}}t| | tjjrHq,|| |< d| | _	q,W d| _| 
  d| _| j| jkrd | _ntd| j dd | jr|   |   | jrtj| jd| j ddd	  | j| j| j| jd
S )Nu   Не dummy task T)r4   Fu)   Выставлен код у dummy-task: u$   Создана подзадача «   »   )r2   text	log_level)r,   r)   name	parent_id)save_preparer.   r@   r,   items
isinstancerC   rA   Z
CmfBackref
is_changedZ_load_changed_fieldsis_newr)   cloned_from_idrf   r3   r5   r-   
CmfCommentrk   rl   )rO   Zchanged_fieldskvr&   r&   r'   r      s4    zCmfTask.save_dummy_taskc             C   s   | j std| j dd | jjrH| jjrH| jtjkrHtd | jj| _dt_| 	  | 
  |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   | jdddddd | S )Nu   Не dummy task T)r4   um   Пожалуйста сохраните задачу перед изменением постановщикаF)r7   ZnotifyemitZauditZ	no_reload)r.   r@   r,   	cmf_ownerrp   oldgcurrent_user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_textr3   )rO   r&   r&   r'   _dummy_save   s6    	
	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]+\Zr0   r=   z-cmf_created_atT)r<   order_byr6   -)sget
project_idintr)   split)rO   Z
max_numberZ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 dy|  W nF tjjk
r } z$td	| d
|j d|j  W dd}~X Y nX X | S )uN    Высчитывает следующий номер для кода
        Z	NOPROJECTznext_code_number-r   z.lock   )timeout   Nzlock release error z, lock_name z
, timeout )APPZREDIS_DBr   rF   
class_nameredislockacquireexistsZincrr   setrelease
exceptionsZ	LockErrorry   debugrk   r   )rO   Zredis_dbsuffixkeyZlock_keyr   next_code_numberer&   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CLOSEDuK    не может быть пустой при плановом списке u'    не может быть дальше ())cache_status_typero   r2   rF   r-   
CmfProject_calc_list_plan_intervalr_   rp   r@   captionrC   rA   CmfDateTimera   plan_end_date)rO   list_plan_start_date_maxlist_plan_end_date_minr&   r&   r'   _calc_alarm_date_list0  s(    

zCmfTask._calc_alarm_date_listc             C   s   | j r| jjs| jjsd S | j jr&d S x8| jD ].}|js>|jr.|jrL|j| _ |jrZ|j| _P q.W | j s| jr| jjjdkr| jj 	 r| jj | _ d S )Nr   )
r]   r2   rp   
componentsZdefault_responsibleZdefault_ownerrw   rF   r   load)rO   compr&   r&   r'   _calc_responsibleM  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 )Nr   )rq   r_   rp   statusrZ   activityrX   plan_start_dater   r    _calc_alarm_dater2   rF   r   Zauto_alarm_dater   r   ra   ry   import_moderd   )rO   )r%   r&   r'   r   f  s,    
zCmfTask._calc_alarm_datec                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}x,| jjD ] }|| jj	kr|j jdgd}qW |s| jr| jd j jdgd}|r|| _ | j st
   dS )u   
        Вычисляем вид деятельности
        Метод вызывается из базового класса.
        :return:
        Nr   r   )rA   r   )r   rp   rq   r2   rX   is_nullhasattrr   newrx   r    r   )rO   Ztmp_activityr*   )r%   r&   r'   r     s,    

zCmfTask._calc_activityc             C   s   d S )Nr&   )rO   r&   r&   r'   _calc_parent  s    zCmfTask._calc_parentc             C   s   | j jr&| j jr&d | _| jdd d S | j js8| j r8d S | j r| j jr| j | j jkr| jr|| j j  | j j| _| jdd ddg}| | | jsd S | j	  t
jjdd| g|d}x(|D ] }|j | j kr| j |_ |  qW d S )NT)r7   r2   rE   r5   r=   )r<   rA   )r2   r   rx   gantt_projectr3   main_gantt_projectr   r>   rE   Ztask_parent_is_changed_hookr-   r
   r!   )rO   rA   child_tasksr8   r&   r&   r'   _do_parent_is_changed  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 )Nr2   logic_prefixztask.gantt_projectu   SimpleLogic: в задаче установлен проект равный проекту родительской задачиrh   )r2   ri   rj   rw   cmf_owner_assistantsr   r   z8responsible.primary_role.structural_project.default_listz1responsible.primary_role.structural_project_forceu   SimpleLogic: Задача добавлена в Структурный проект Главной роли исполнителяu   SimpleLogic: Проект сменен, т.к. в Главной роли исполнителя указано менять проект)tree_parentrp   r]   r5   r2   rl   r>   r   rm   r-   rs   r3   r@   Z_node_parentr?   primary_rolestructural_projectZstructural_project_force)rO   Z	sl_reasonr2   Zstruct_projectZstruct_project_forcer&   r&   r'   _HACK24052023_calc_parent  sX    


z!CmfTask._HACK24052023_calc_parentc             C   sb  | 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rtjj| jddgd| _ | j s| j| _ | j
jrL| j rL| jdkrL| jjdkrL| jjdd | jrFtd x | jD ]}| j |_ |  q,W d | _ | jd	kr^d | _ d S )
N)z	task.epicztask.subprojectztree_parent.parentepicZtree_hidden)r2   sys_typerA   T)r6   u   Скрываем задачу в дереве проекта, её дочерние элементы вставляем вместо неёztask.gantt_project)r   r   rp   r2   rx   r>   r-   Z	CmfFoldergetrq   r\   Z
tree_nodesr   r@   r3   )rO   childr&   r&   r'   _calc_tree_parent  sD    


zCmfTask._calc_tree_parentc             C   s0  | j rH| j}x:|rF|jjdkrF|ddg |jdkr>|| _P |j}qW | 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| _| jjr,| jr
tj| jd| j ddd  n"tj| jjd| j ddd  d S )Nr   r   r   )z	task.epicztask.subprojectr
   ztask.subu2   У подзадач нельзя менять EpicT)r4   u@   У подзадач нельзя менять Подпроектu(   Добавлена подзадача «rg   rh   )r2   ri   rj   u$   Удалена подзадача «)rq   r   rF   r   r>   r   r5   rp   r   r   r@   
subprojectr-   rs   rk   r3   rx   )rO   Ztmp_tree_parentr&   r&   r'   r|   N  s>    




zCmfTask._calc_parent_taskc             C   s&   | j r
d S | jjsd S tj|  d S )N)rq   r   rp   r-   CmfTimeTrackerZtimetracker_task_change_status)rO   r&   r&   r'   _calc_timetrackerx  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 )N)rq   r   rp   r2   r5   	main_listZ_load_perm_fieldsro   rF   r-   ZCmfDocumentperm_parent)rO   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 )r,   rk   r)   )to_json).0ir&   r&   r'   
<listcomp>  s    z1CmfTask.get_cache_fields_json.<locals>.<listcomp>rX   c             S   s   g | ]}| d ddgqS )r,   rk   r)   )r   )r   r   r&   r&   r'   r     s    tags
is_checkedrl   activity_id)r    get_cache_fields_jsonrX   r   r   rl   r   )rO   ret)r%   r&   r'   r     s    



zCmfTask.get_cache_fields_jsonc             C   s   d }d }xb| j D ]X}|jsq|jdkr(q|jjrH|d ksB|j|krH|j}|jjr|d ksb|j|k r|j}qW |s|rtjj	 }||fS )Nr   )
rX   Zaffect_gantt_taskr   r   is_not_nullr   rC   rA   r   ra   )rO   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    установлена в соответствии с планом списка)	rX   rp   lenr   r   r_   r   r@   r   )rO   r   r   Zself_plan_shiftr&   r&   r'   _calc_plan_list  sL    

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_   rp   r   r   r   daysrF   r@   
_calc_name)rO   Z	date_diffr&   r&   r'   _calc_plan_nolist  s    
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)
rX   rp   rq   r_   r   r   r   r   r   r   )rO   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: Задача согласована автоматически, т.к. это Непроектная задачаrh   )r2   ri   rj   u   SimpleLogic: Задача согласована автоматически, т.к. согласование отключено в Fu   SimpleLogic: Выполнен сброс согласования, т.к. сменился Постановщик или Проектu   SimpleLogic: Задача согласована автоматически, т.к. постановщик - руководитель.)rq   approvedrp   rw   r2   rF   r   r-   rs   r3   _get_sl_optionssl_task_need_approveZsl_controller_strr   r,   ry   current_personZ
cmf_import
is_defined)rO   
sl_optionsr&   r&   r'   _calc_approved,  sD    
$"zCmfTask._calc_approvedc                s   t t  }| ddg x4| jD ]*}||j x|jD ]}|| q<W q$W | jjrxTt | jj	t | jj
 D ]8}|ddg ||j x|jD ]}|| qW qtW | jr| jjdsx| j D ]}|| qW t|S )Nzlists.cmf_ownerzlists.cmf_owner_assistantsrw   r   zCmfProject:)r   r    
get_ownersr>   rX   addrw   r   rp   rx   r   r2   rl   rF   
startswithr!   )rO   r#   r$   Zownerslstowner)r%   r&   r'   r   ^  s     zCmfTask.get_ownersc                s&   | j r
d S | jdkrd S t   d S )Nr   )waiting_forr   r    _calc_waiting_for)rO   )r%   r&   r'   r   v  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 x| j jjdkrH| j jjdk}|s | jjddds | j j| jdk}|rH| j jjdkrD| jp@|| _| js| j|kr|sj|| _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rD| j|krD| jrD| jrD| 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*rd| j+rdtj(j)dd| j+gdddgd!d| j,ggd}|sd| j+-d"g | jd| j+_ | j+"  td# |r|j.rtj|  kr| j/s| jjddd$}|r|| _ td% q| j jjdkrd| _| jdks| jrd| _d| _dS | j jjdkr| j/r| jd| _ td& q| js0| j0  | j jjdkr\| j| j1 kr\| j0  | 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|j2rtd+dd
 td, | j jjdkr| jp|| _tj | d-dd"  | j jjdkrR| j|krR| jp:|| _tj | d.dd"  | jsd| j0  | j jjd*kr| j| j1 kr| j0  tj | d/| j j! dd"  dS P qW dS )0uS   
            Ф-я вызывается из базового класса
        NimportFr   T	IN_REVIEWZapprove2Zapprove1_reviewu[   Только Владелец проекта может согласовать задачу)r4   r   open)status_coder+   )r   IN_PROGRESSZapprove3_notassigneduh   SimpleLogic: Задачу переключили на Постановщика/Руководителя(u   ), т.к. не указан Будильник. Установите будильник, чтобы задача отобразилась у Исполнителяrh   )r2   ri   rj   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>r5   r=   r   z!=)r<   um   Для закрытия задачи необходимо закрыть все дочерние задачиu_   Вы закрыли задачу у которой есть Открытые подзадачиr,   zchild_tasks.cache_status_typeu}   Родительская задача закрыта автоматически т.к. закрыты все дочерние)r+   u   Спасибо! Статус установлен в "Подтверждение закрытия", для проверки постановщиком или владельцем проектаu   Спасибо! Статус изменен на «Закрыто» т.к установлен флаг «Без подтверждения».uO   SimpleLogic: Задачу переключили на Постановщика(u   ), т.к. статус=''r   uT   Нельзя брать в работу несогласованную задачу.um   Внимание! Вы взяли задачу без согласования с руководителем.u^   SimpleLogic: waiting_for  установлен т.к. статус снижен в in_progressui   SimpleLogic: waiting_for установлен т.к. статус перешел из open в in_progressu[   SimpleLogic: будильник установлен т.к. статус сменен на )3r   rp   r   r]   rw   r2   r_   r   osenvironr   r   rF   r   r   r   status_typeapprove_forapprove_for_placeZsl_only_owner_approver   ry   r   r   r@   rx   r   rq   r)   workflowget_default_statusr-   rs   rk   r3   Z,sl_deny_closing_task_before_closing_subtaskshas_child_tasksr   r   r   r
   r   t%   sl_сlose_task_after_closing_subtasksr5   r,   r>   Zsl_task_only_owner_closeZ
no_controlrd   ra   Zsl_deny_no_approve)	rO   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   ~  sL   
 $2


	


 $




*

zCmfTask._calc_wf_simple_logicc                s   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s|| | _d S )N)r   i  )r    _calc_deadliner   rp   r2   r_   rq   rZ   r   Zsl_deadline_shiftr`   r   ra   rb   rc   cmf_created_atagerw   ry   r   rF   )rO   r   Z
days_shiftshiftra   )r%   r&   r'   r    s<    

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 )NrX   fix_versionsr,   z
members.id)rA   )r>   r-   CmfListr   rX   remover  )rO   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 )NrX   r,   z
members.id)rA   )r>   r-   r  r   rX   r^   )rO   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*   )r-   CmfActiveEntityFilterr   Zadd_active_entity)rO   	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_tag)rA   T)r7   )r-   r  r   r  r   r	  r3   )rO   r  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 )NrX   r5   zparent_task.nameu   Укажите from_idT)r4   u   Укажите to_idu(   Не могу перместить из rk   )r,   rA   u5   Нельзя переместить задачу в "u/   ", так как она находится в ""u&   Не могу перместить в )r>   r@   r   Zget_cls_by_tuuid_strr-   r  r
  r  r  r
   r5   r,   rF   r   r  r   rk   )rO   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}|sl| jjshdS dS |s|| j| dS )Ntoken_sanitizedFr   u   #№@r9   rk   ILIKEaliasz%"z"%)r<   rA   T)lstripr-   ZCmfTagr   rk   rp   r   r^   )rO   	only_namectxr  tagr&   r&   r'   _process_tag_token/  s$    

zCmfTask._process_tag_tokenc             K   sz   |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}|sl| jjshdS dS |sv|| _dS )Nr  Fr   u   #№@r9   rk   r  r  z%"z"%)r<   rA   T)r  r-   ZCmfLogicTyper   rk   rp   r\   )rO   r  r  r  ltr&   r&   r'   _process_logic_type_tokenT  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}|s| jjrdS dS |s|| _dS )Nr  F)#u   №@u   #№@   
user_localz==Tr9   rk   r  %Zlogin)r<   )	r   r  r   r-   	CmfPersonr   rk   rp   r]   )rO   r  r  r  _filterpersonr&   r&   r'   _process_responsible_tokeny  s&    

z"CmfTask._process_responsible_tokenu   Январьu   Февральu   Мартu   Апрельu   Майu   Июньu   Июльu   Августu   Сентябрьu   Октябрьu   Ноябрьu   Декабрь)r   rh         r           	   r         c             C   s0   |  }|  }|d| d| d| fkS )Nr  u   №r  )lower)rO   stringZhashtagr&   r&   r'   hashtag_cmp  s    zCmfTask.hashtag_cmpc       	      K   s  |d }xD| j  D ]2\}}| }|d| d| d| fkrP qW dS |s| jsl|| jj krld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 )Nr  r  u   №r  FT)r[   r   r   )ZdayZhourZminutesecondZmicrosecondr+  )monthsr   )r0  r   )_monthsrn   r,  rq   rk   rx   r`   ra   rb   rc   replacemonthr   r   rF   Zyearr   )	rO   r  r  r  Z	month_idxr3  r   r  r   r&   r&   r'   _process_month_token  s6     
zCmfTask._process_month_tokenc             C   s   | j dd dS )uG    Ф-я вызывается из базового класса
        T)r  N)_calc_from_name)rO   r&   r&   r'   r     s    zCmfTask._calc_namec             C   s  t jjj}| jjs2| jjs2| jjr&|s2| jjs2d S | jjp<d}|	 }g }|rX|sXg | _xlt
|D ]`\}}| d}t  }	|	d= | jf |	rqb| jf |	rqb| jf |	rqb|| |sbqbqbW g }d}
|r|| t|d }|| d||< |r4x2t| jdd d	D ]}d
}
|d|j  qW |
rP|rP||  d7  < d|| _| 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.,;:?!rO   Fr   .c             S   s   | j jS )N)rk   rF   )r  r&   r&   r'   <lambda>      z)CmfTask._calc_from_name.<locals>.<lambda>)r   Tr  r   z	task.epicadd_object_type)rA   1ZEpiczEpic zEpic 1)ry   Zglobal_settingsZshow_task_title_tagsrF   rk   rp   r   r   r]   r   	enumerater,  striplocalsr   r  r  r#  r^   extendr   rstripsortedjoinr   rq   r2   r>   r:  r   )rO   r  Zname_tags_boundrk   Zname_tokensZundefined_tokensidxtokenr  r  Zneed_dotZdot_token_posr  r&   r&   r'   r5    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)ztask.subprojectgantt)z	task.epicztask.gantt_subprojectr!   z
pfeed.basepost)r\   rp   rq   r   ui_view_formui_namer,  )rO   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 )	Nr2   r   r5   r   zgantt_project.op_gantt_taskrE   ztask.gantt_projectz main_gantt_project.op_gantt_task)r>   r   r5   r   r2   r   )rO   r&   r&   r'   _calc_gantt_project6  s    

zCmfTask._calc_gantt_projectc          	   C   sr  | 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 | j	s| j
r| j
ddg | j
jdkr| j
| _	n
| j
j	| _	| j	s| jd	kr| j j  | j j| _	| j	}|s| jdkr| }t  | jstj| d }|| _| j
js
| j	jr&|| j_	| j
| j_
| j  | jsd| j jrd| j rd| j jjdkrd| j | j_| j  W d Q R X d S )
Nr   )z	task.epicztask.subprojectztask.gantt_projectu_   task.epic, task.subproject и task.gantt_project не могут быть без ПроектаT)r4   r   r   ztask.gantt_project)z	task.epicztask.subproject)r2   rF   r   r   r@   rE   r-   CmfGanttTaskcreate_gantt_taskr   r5   r>   r   r   cmfutildisable_aclrp   r3   rq   r0   )rO   Zcur_gantt_projectrE   r&   r&   r'   r   E  sB    








zCmfTask._calc_gantt_taskc             C   s<   | j jr| j| j j| j j | jjs.| jjr8| j  dS )u   
        Изменяем счетчики Оперативной Гант-задачи при изменении задачи
        N)	r   rp   rE   Ztask_status_is_changed_hookrx   r   r   r   Ztask_plan_dates_is_changed_hook)rO   r&   r&   r'   _calc_op_gantt_task_counters~  s    z$CmfTask._calc_op_gantt_task_countersc                s  | j r2| jj s2| jdkr2|  }|jr2tddd | jsBt  S | j	sR| j sRd S t
 }xF| jddD ]6}|j|  krf|jdsf|jdsf||j qfW d|ksd	|kr@| 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r,|d d	|kr@|d	 d|kr| jjd| d | jrx| 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rl| jj r8| jdkr8| jjdkr8| jjd| d n*| jjrb| 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rP| jjd | d x@| jjD ]4^}}}|d!kr|jd"kr| jjd|| d qW |d d#|krt| jjd$| d |d# |r| jjd%| d d S )&Nr   ud   Редактирование запрещено, так как задача в статусе CLOSEDT)r4   )rp   Zcache_Z_idr2   r0   zPPP-TSK-CREATE)r*   Zuse_new_projectzPPP-TSK-MOVE)r*   r]   zPPP-TSK-ASSIGNzPPP-TSK-ASSIGNABLE)userr*   rw   zPPP-TSK-MODIFY-OWNERr5   rX   r   zPPP-TSK-CLOSEzPPP-TSK-RESOLVEzPPP-TSK-TRANSITION
spectatorszPPP-VW-MANAGErZ   zPPP-TSK-DEADLINEr_   	executorszPPP-TSK-ASSIGN-EXECUTORSr^   r   Zperm_security_levelzPPP-TSK-SET-SECURITYzPPP-TSK-EDIT)rp   r   r   r   Zsl_readonly_closed_taskr@   r0   r    check_edit_permrq   r   valuesr   Zproject_perm_allow_fieldsr   endswithr   r2   r1   rx   r   r.   r	  r]   rF   rw   r_   rQ  Z_changes)rO   r   Zchanged_fields_to_checkZfieldZchange_actionZ
change_obj_)r%   r&   r'   rR    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 )	Nri   r0   rw   rX   r]   rQ  zPPP-TSK-DELETE)r*   )
r>   ri   rk   rw   ry   rz   r0   r1   r    check_delete_perm)rO   )r%   r&   r'   rV    s    
zCmfTask.check_delete_permc             C   sf   | j sb| jjrb| jjsb| jrbxDtjjdd| jgddddgdddgggdD ]}| j|_|	  qJW dS )u  
        При создании задачи - у нее не указывается имя сразу, но уже создается нотифай с пустым именем.
        Но нотифай по str-полям когда пусто меняется на имя - не создается и не обновляет информацию в созданных нотифаях.
        Поэтому мы сделал этот ХАК с нарушением слоёв.
        Zobj_idz==r9   ri   r6  N)r<   )
rq   rk   rp   rx   r-   	CmfNotifyr!   r,   ri   r3   )rO   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r^x0t| jjt| jj D ]}|j	dkrF|}qFqFW |sfd S t| j}xL|D ]D}||krqv|j	dkrqv|j
dkrqv|j
dkrtd | j| qvW d S )Nr   Fzlist.agile_sprintr   r   u\   Внимание! Задача перемещена из Запущенного списка)r2   rF   r   Ztask_allow_multiple_sprintsrX   rp   r   r   rx   r   r   r@   r	  )rO   Z
add_sprintappended_listZcurrent_sprintsZ
cur_sprintr&   r&   r'   _calc_sprints  s*    





zCmfTask._calc_sprintsc          /      sp   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/g/}t   | S )0Nr.   zparent.project_typezparent.auto_alarm_datezparent.logic_prefixzparent.activity.prefixz"parent.task_allow_multiple_sprintsr5   zparent_task.logic_prefixzparent_task.listszparent_task.lists.logic_prefixz#parent_task.lists.cache_status_typezparent.sdesk_feedbackzparent.default_gantt_task_typer   ztags.tag_categoryzlists.plan_start_datezlists.plan_end_datezlists.ordernozlists.perm_has_aclzlists.sys_typez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.prefixzcomments.log_levelr   r   Zcmf_modified_byr   timetracker_historyr  r   r   r   rE   z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_approverr   )r    r?   )rO   rA   )r%   r&   r'   r?   1  s`    zCmfTask.save_preload_fieldsc             O   s:   t j| d d| _| jdd t jj| df|| d S )Nr   Zapprove4T)r7   Zapprove_started)r-   
CmfApproveZstart_approve_processr   r3   CmfEventdo_event)rO   r#   r$   r&   r&   r'   start_approvef  s    zCmfTask.start_approvec             C   sR   |  dddg | jjj| _x| jD ]}| j| q$W |   tj	| d d S )Nzstatus.trans_approvedzstatus.trans_approved.status_toapprovers_forZapprove_success_full)
r>   r   Ztrans_approved	status_tor`  r	  r3   r-   r]  r^  )rO   approver_forr&   r&   r'   _approve_approvedl  s    zCmfTask._approve_approvedc             C   sR   |  dddg | jjj| _x| jD ]}| j| q$W |   tj	| d d S )Nzstatus.trans_rejectedzstatus.trans_rejected.status_tor`  Zapprove_rejected)
r>   r   Ztrans_rejectedra  r`  r	  r3   r-   r]  r^  )rO   rb  r&   r&   r'   _approve_rejectedt  s    zCmfTask._approve_rejectedc             C   s<   |  dddg | jjj| _x| jD ]}| j| q$W d S )Nzstatus.trans_updatedzstatus.trans_updated.status_tor`  )r>   r   Ztrans_updatedra  r`  r	  )rO   rb  r&   r&   r'   _approve_updated|  s    zCmfTask._approve_updatedc             K   sl   | d}| d}| d}tjj | |tjdd}|rL|jf d|i| | jtj tj	| d d S )Napprove_group
resolutionri   r"  )r*   rf  ZapproverZapprove_typeZapprove_success_one)
r   r-   r\  ry   rz   Z_approve_oner`  r	  r]  r^  )rO   r$   rf  rg  ri   Zapprover&   r&   r'   r     s    



zCmfTask.approve_onec                s   dt _t j||S )NT)ry   r{   r    create)r"   r#   r$   )r%   r&   r'   rh    s    zCmfTask.createz(?P<code>[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]+).*
        Nr6  r)   INr0   c             S   s   g | ]
}|j qS r&   )r,   )r   r0   r&   r&   r'   r     s    z.CmfTask.find_related_tasks.<locals>.<listcomp>)r<   rA   r   )_TASK_CODE_SEARCH_REfindallr-   r
   r!   )r"   ri   rA   Zprojectsr   ZcodesZfilter_r&   r&   r'   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r| dg g }x"| jD ]}|jdkr@|| q@W x$|D ]}| j| | j| qbW | j s| jjr| dg g }x"| jD ]}|jdkr|| qW x$|D ]}| j| | j| qW dS )u   
        При добавлении в список правильно выбирать поле lists или fix_versions
         в зависимости от типа списка
        Nzfix_versions.logic_prefixzlist.releasezlists.logic_prefix)rq   r  rp   rX   r>   r   r^   r	  )rO   r   r*   r&   r&   r'   r     s,    



zCmfTask._calc_fix_versionsc             C   sl   t | j}|| j | jjr,|| jj | jjrB|| jj dd |D }ttjj	dt |id d S )Nc             S   s   h | ]}t |jqS r&   )strr,   )r   re   r&   r&   r'   	<setcomp>  s    z4CmfTask.process_lists_count_cache.<locals>.<setcomp>Zlist_ids)r$   )
r!   rX   r?  r  rp   rx   schedule_deferred_jobr-   r  Zrecalculate_count_cache)rO   rX   Zids_setr&   r&   r'   process_lists_count_cache  s    
z!CmfTask.process_lists_count_cachec          
      sR	  | j r~| js~| js~dt_| jjr| jr| jjjdkr| j	ddddddd	g | 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 r$t  |   W d Q R X |   |    | !  | "  | #  | $  | %  t& j|ddi|}| '  |S | jr| ( S | j)js| j r| | j)krt*ddd | jjr| +  | ,  | -  | .  | /  | jjr2| j0r2x4t1| jj2t1| jj3 D ]}|| j0krd | _0qW | j0sx$| jD ]}|j4dkrB|| _0P qBW | j0sx$| jD ]}|j4dkrp|| _0P qpW | jjr| j0r| 	dg | j0j4dkrx6t1| jj3t1| jj2 D ]}|j4dkr|| _0P qW | j0jr | j0r | j0| jkr | j| j0 | jjs2| j rF| jrF| jjjdkrF| j	ddddddd	g | jj
r| jj
| jkr| j| jj
 d
| jj
j d| jj d}tj| |dd  | jjrF| jj2rF| jj2jdkrF| jj2j
  | jj2j
}|rF|| jkrF| j5| d|j d| jj2j d}tj| |dd  | jjrtj6sxLt1| jj3t1| jj2 D ]0}|j7dkrrt*d|j d| j ddd qrW xLt1| jj2t1| jj3 D ]0}|j7dkrt*d|j d| j ddd qW | 8  |9ds| jjr| j:rt;t1ddd}	|	| jj3}
|	| jj2}|
| }||
 }t<||grtj=j>j?| j@jt;|t;|dd  | A  |   |   |   |   | B  | jCjr| jCd!kr| j4d"krt*d#| jC d$dd | D  | jEjrtjFjG| d%f|| | $  | %  t& j||}| j7jr| j7j3dkr| jHr| jI  x,| jID ]"}t  |J  W d Q R X qdW | K  | jr| jjs| j r| jj rt  |   W d Q R X | jjr| L  | jMd&krptjNO|  | j r| jPQ  | jdd' | j s:| jr:tjRS|  | j7jrp| j7dkrp| jjTrptUtj=jV| j@jgd( | jjs| jWjrtUtjXjY | j otZ| jd)kptZ| jWd)k}|s| jjs| jWjs| jjr| 	d*g | [  x*d+D ]"}t\| |jrtUtj]jY P qW | j)rR| j)j4 d,krR| j)jsF| j rRtUtj=jY | j)j2r| j)jr| j)j2j4 d,krtUtj=jY | j4jr| j4j2d,krd)| _^| j_jr| jrt`| jjtjar| jb| j_ | j7j	r| j7dk	r| ctjdj@ | jed)d- | jf	r&| j4d.k	r&t*d/dd | '  | jgj	sB| jhj	rNtjij|  |S )0NTr   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_taskuU   SimpleLogic: Задача добавлена в Cписок по умолчанию "u   " проекта "r  rh   )r2   ri   rj   rv   FuK   Нельзя добавлять задачу в eё же подзадачи)r4   zlist.agile_sprintz	list.basezmain_list.logic_prefixuS   SimpleLogic: Задача удалена из Cписка по умолчанию "r   uS   Нельзя добавить задачу в Завершенный список "z" - "uU   Нельзя удалить задачу из Завершенного списка "from_sync_subtasks)rX   returnc             S   sJ   t  }x>| D ]6}|ddg |jdkr*q|jdkr6q||j qW |S )up  Фильтрует lists - оставляет только незакрытые спринты и возвращает множество ID этих спринтов

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

                Returns:
                    set: множество не закрытых спринтов
                r   r   zlist.agile_sprintr   )r   r>   r   r   r   r,   )rX   Zsprints_idslist_r&   r&   r'   get_correct_sprintsh  s    	


z)CmfTask.save.<locals>.get_correct_sprints)task_idsprints_to_add_idssprints_to_remove_ids)r$   )r8   r!   rF  rE  )z	task.epicztask.subprojectu   Вид отображения uk    временно не поддерживается, используйте "task", "list", "post", "gantt"Zspectators_changedzproject.servicedesk)r7   )r#   r   r  )r   r2   r   r]   r   r   z	task.epic)rY   )z	task.epicztask.subprojectztask.gantt_projectus   DEV: Недопустимое перемещение простой задачи в структуру дерева)krq   rk   r.   ry   r{   r2   rp   rF   r   r>   default_listrX   r^   r-   rs   r3   r|   r~   r   r}   r   r   r   r   r   r   Zneed_approver   rL  rM  r_  r   r  r   r   r   r   r   r    r   r   r5   r@   r5  rX  r   _calc_estimate_workr   r   r   rx   r   r   r	  r   r   rZ  r   r  r!   anyr
   _sync_subtask_sprintsZapplyr,   _calc_logic_type_change_guard_calc_agile_story_pointsrG  _calc_structural_listrP  r]  r^  rZ   Zstaff_control_blocked_personsZcalc_staff_control_blockedrN  r   parent_logic_prefixCmfSDeskSlaTriggertask_changed_hookr  rd   ZCmfSDeskSlaCycleZupdate_cycle_goalsZsdesk_feedbackro  Zsdesk_send_feedback_requestr  r  recalculate_cacher   rp  getattrr  cache_child_tasks_countr   ro   r   Zhook_task_tags_changedZ_clear_notifyr   Z_update_opened_notifiesr   r]   rQ  CmfTaskResAssignsync_task_resources)rO   r#   r$   	audit_msgZinstZremoved_listre   rY  Zold_default_listrt  Zsprints_newZsprints_oldsprints_to_addsprints_to_removeZself_instancer"  Zis_new_with_listsrQ   )r%   r&   r'   r3     s^   

$
$$



(


 &$
,($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	rDxjt| 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 qW d S | jjrXx~t| jjD ]n}|jd
krp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\W xt| 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 qW t| jd}| j jrz| j j|d< | jjjr| jjj|d< | jjjr| jjj|d< |rxd| 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 qW |rzxX| jD ]N}|jd
ks(||
krFq(|j| jj|jj||jj|jj||jjdd q(W |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:xV| jD ]L}|jd
ks||
krq|| jjd |j| jjd dd|||d qW | jjdkr| jjdkrx`| jD ]V}|jd
ks^||
kr|q^|j| jjd||||	d  |j| jjd d!d|||d q^W d S )"Nr   )ZstartedclosedrX   agile_story_pointszop_gantt_task.sched_durationzop_gantt_task.sched_workzop_gantt_task.actual_workr   r   r   r^   )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  z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  rp   rE   Zsched_durationrX   
sched_workr   r   rx   rq   r>   rF   actual_workr   Zhistory_otr_addr,   Zhistory_rte_addr^   dict
time_spentremaining_estimateZend_date)rO   r  	task_listr[  r  r  r  r  r  r  Zappendedr   paramsr&   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}x(|D ] }|j | j krl| j |_ |
  qlW d S )Nr2   rE   r5   r=   )r<   rA   )r2   r   r   r   r5   r>   rE   r-   r
   r!   r3   )rO   rA   r   r8   r&   r&   r'    _change_parent_and_gantt_projectw	  s    


z(CmfTask._change_parent_and_gantt_project)TEXKOM_db_deletec      
      O   s4  |sd S d | _ | jdd ddd| gdd| gdd| gg}x,tjj|ddD ]}|j|d	|i| qJW x,tjj| dd
D ]}|j|d	|i| qxW x,tjj| dd
D ]}|j|d	|i| qW x*tjj| ddD ]}d |_	|jdd qW x@tj
jddd| gdd| ggddD ]}	|	j|d	|i| qW d S )NT)r7   r9   r8   z==r   r5   )r<   r6   r  )r8   r6   )r   r6   r:   r;   )rE   r3   r-   rJ  r!   rH   rI   CmfTaskCodeHistoryr
   r   rJ   )
rO   r  r#   r$   r!  Z
gantt_taskrS   r)   r8   rT   r&   r&   r'   _delete_relations	  s     (zCmfTask._delete_relationsc            O   s   x0t jj| |dgdD ]}|j|d|i| qW x0t jj| |dgdD ]}|j|d|i| qHW x,t jj| |dD ]}|j|d|i| qvW d S )Nz-cmf_created_at)r8   r6   r   r  )r*   r6   )r-   rL   r!   rH   rM   rN   )rO   r  r#   r$   rW   r&   r&   r'   _delete_history	  s    zCmfTask._delete_historyc             O   s~   x(t jj| ddgdD ]}|j|| qW x(t jj| ddgdD ]}|j|| q@W x$t jj| ddD ]}|j|| qfW d S )NTr  )r8   cmf_deletedr   )r*   r  )r-   rL   r!   restorerM   rN   )rO   r#   r$   rW   r&   r&   r'   _restore_history	  s    zCmfTask._restore_historyc                s   |  ddddddddd	d
g
 | jr@x| jD ]}|j|| q,W | j|| | j|| | j|| | j|| | j|| t j||}| j	r| j	j|| | j
s| jrttjj |   | jr| jj dkrttjj | jr| j|  |S )Nri   r0   rw   sdesk_sla_cyclesr   r5   rX   r  r]   rQ  z	task.epic)r>   r  rH   _delete_task_resourcesr  _delete_timetracker_history_delete_subtasksr  r    rE   rX   r  ro  r-   r  r  rp  r5   r   r   r
   child_task_delete)rO   r#   r$   Zsdesk_sla_cycleres)r%   r&   r'   rH   	  s*    zCmfTask.deletec                sD  t  j||}| ddg | jr0| | j ntjj| d d |   | 	  | j
|| |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dd	 |S )NrE   r5   )r8   Zbaseliner2   	recursiveFz	task.epicT)r7   zparent_task.has_child_taskszparent_task.parent_task)r    r  r>   rE   Z_restore_child_objectr-   rJ  rK  _restore_timetracker_historyr  _restore_task_resourcesr   r   _restore_epics_subtasks_restore_subtasksr  r3   r5   r?   _calc_cache_branch_gantt_path_recalc_gantt_path)rO   r#   r$   r  r2   )r%   r&   r'   r  	  s<    	

zCmfTask.restorec             O   sV   | dd}d|d< tjj| |d}x|D ]}|j|| q*W tj| ddd  d S )Nr  Fr  )rl   r6   u$   Журнал работ удаленrh   )r2   ri   rj   )r   r-   rK   r!   rH   rs   r3   )rO   r#   r$   r  rU   rV   r&   r&   r'   r  
  s    
z#CmfTask._delete_timetracker_historyc             C   s>   t jj| dd}x|D ]}|  qW t j| ddd  d S )NT)rl   r6   u0   Журнал работ восстановленrh   )r2   ri   rj   )r-   rK   r!   r  rs   r3   )rO   rU   rV   r&   r&   r'   r  
  s    
z$CmfTask._restore_timetracker_historyc             O   s`   | dd}tjj| |d}x*|D ]"}tjj|j|dr"|j|| q"W tj| ddd  d S )Nr  F)r   r6   )r,   r6   u!   Подзадачи удаленыrh   )r2   ri   rj   )	r   r-   r
   r!   r   r,   rH   rs   r3   )rO   r#   r$   r  
tasks_listr8   r&   r&   r'   _delete_epics_subtasks#
  s    
zCmfTask._delete_epics_subtasksc             O   sB   t jj| dd}x|D ]}|j|| qW t j| ddd  d S )NT)r   r6   u-   Подзадачи восстановленыrh   )r2   ri   rj   )r-   r
   r!   r  rs   r3   )rO   r#   r$   r  r8   r&   r&   r'   r  1
  s    
zCmfTask._restore_epics_subtasksc             O   sP   | dd}tjj| ||d}x|D ]}|j|| q$W tj| ddd  d S )Nr  F)r5   r6   r   u!   Подзадачи удаленыrh   )r2   ri   rj   )r   r-   r
   r!   rH   rs   r3   )rO   r#   r$   r  r  r8   r&   r&   r'   r  <
  s    
zCmfTask._delete_subtasksc             O   sB   t jj| dd}x|D ]}|j|| qW t j| ddd  d S )NT)r5   r6   u-   Подзадачи восстановленыrh   )r2   ri   rj   )r-   r
   r!   r  rs   r3   )rO   r#   r$   r  r8   r&   r&   r'   r  H
  s    
zCmfTask._restore_subtasksc             O   s2   t jjdd| gd}x|D ]}|j|| qW d S )Nr2   z==)r<   )r-   r  r!   rH   )rO   r#   r$   assignments
assignmentr&   r&   r'   r  S
  s    
zCmfTask._delete_task_resourcesc             O   s4   t jjdd| gdd}x|D ]}|j|| qW d S )Nr2   z==T)r<   r6   )r-   r  r!   r  )rO   r#   r$   r  r  r&   r&   r'   r  X
  s    
zCmfTask._restore_task_resourcesc                s   |  ddg |jdkr2tjs2| j  tjj| _| j	sJ| j
sJ| jdd | jdkrr|rr|jdkrrtjj| |d t j|d|i|S )	Nr2   r  r   T)r7   zproject.servicedesk)commentr  )r>   rj   ry   r   Zcmf_modified_atrd   rz   r,   Zcmf_modified_by_idrq   Zis_recursion_saver3   r  r-   r  r  r    _comment_save_hook)rO   r  r#   r$   )r%   r&   r'   r  ]
  s    

zCmfTask._comment_save_hookc       	         s   |sg }|sdg}|sg }|dddgddddggd	d
ddgd
dd ggg}|oT| d}|rl|rl|dd|gg}|d
 |d t j|f||||d|S )Nrk   r   z!=r   r   ri  zlist.agile_sprintz	list.baser9   r   Ztrashz==rl   r=   r2   )object_fieldsr<   rA   r   )r   r^   r    field_options_list)	r"   relation_field_namer  r<   rA   r   filter_by_projectr$   rl   )r%   r&   r'   lists_options_listp
  s"    

zCmfTask.lists_options_listc       
         s   |sg }|sdg}|sg }|dddgg}|o4| d}| dd }	|r\|sN|	s\|dd|gg}|d |d	 t j|f||||d
|S )Nrk   r   z==zlist.releaserl   searchr=   r   r2   )r  r<   rA   r   )r   r^   r    r  )
r"   r  r  r<   rA   r   r  r$   rl   r  )r%   r&   r'   releases_options_list
  s    

zCmfTask.releases_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 )Nrl   r=   r9   r   zlist.agile_sprintz	list.base)r  r<   rA   r   )r   r  )r"   r  r  r<   rA   r   r$   r&   r&   r'   main_list_options_list
  s    zCmfTask.main_list_options_listc                sp   |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|S )	Nrl   r=   r  r9   r   z	task.epicztask.subproject)r  r<   rA   r   )r   r    r  )r"   r  r  r<   rA   r   r$   )r%   r&   r'   parent_task_options_list
  s    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 )Nr9   Z
cmf_hiddenr=   Frl   r  rk   r  r  ri   r  )r<   rA   r   )r   r-   ZCmfComponentr!   )r"   r  r  r<   rA   r   r$   r  r&   r&   r'   components_options_list
  s    :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   r=   ztask.gantt_projectr  rl   TZinclude_hidden)r  r<   rA   r   )r   r    r  )r"   r  r  r<   rA   r   r$   r  )r%   r&   r'   gantt_project_options_list
  s    z"CmfTask.gantt_project_options_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 t j|f||||d|S )NrX   )r  r<   rA   r   )r  Zaffected_versionsr   r5   r   r   )r  r  r  r  r  r  r    r  )r"   r  r  r<   rA   r   r$   )r%   r&   r'   r  
  s"    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)   rA   r   zAuto task reopenu'   Переоткрываем задачу)r2   ri   NZdefault_project)rA   zNew auto task for r   z
) project 
r6  )r)   rk   ri   r]   rw   rY   r2   r   )printhashlibZmd5encodeZ	hexdigestr-   r
   r   r   r   r  r   r_   rd   rs   r3   r   rC   rA   r   Zget_obj_by_tuuid_strrk   r)   r,   rF   )rk   ri   Z
extra_textrY   responsible_idZcmf_owner_idrl   _kwargsZtask_keyZ	task_hashZ	task_coder8   r]   rw   r2   r&   r&   r'   	auto_task
  s>    



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 }xX|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 qFW |S )	Nr  z==T)r<   r   r   r  )Zin_progressr   )
r-   r   r!   r,   r  r
   r(   r   r   rF   )r"   r<   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 )N)r   rp   r2   r   r   r   rX   r\   r   	scheme_wfcalc_workflow)rO   r&   r&   r'   r   3  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 )Nztask.gantt_projectua   Нельзя изменить Логический тип задачи на Гант-проектT)r4   uT   Нельзя изменить Логический тип у Гант-проекта)r\   rp   r   rx   r@   )rO   r&   r&   r'   r|  F  s    z%CmfTask._calc_logic_type_change_guardc             C   sB   | j js*| jjr&| jdks*| jjdks*d S |   | | j  d S )N)z	task.epicztask.subprojectztask.gantt_project)z	task.epicztask.subproject)r5   rp   r\   r   rx   r  r  )rO   r&   r&   r'   r~   U  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|jkrf|j| _|jd	kr~|| _d | _n|jd
kr|| _xtjj| dddddddgdD ]}d}|j| jkr| j|_d}| jd
kr| |_| j|_d}nR| jd	kr| |_d |_d}n4|j| jkr&| j|_d}|j| jkr@| j|_d}|j	rh|
|  |jj|jjkrhd}|rz|jdd |j	r|jd |d d q||  qW d S )Nd   uM   DEV: Защита от рекурсии: _recalc_gantt_path: if r_count > 100T)r4   r   r   r   r   ztask.subprojectz	task.epiccache_branch_gantt_pathr5   r  )r5   rA   F)r7   r   )r5   r_count)r@   r>   r   r   r   r   r-   r
   r!   r  r  r  r   rx   r3   r  _check_relations)rO   r5   r  ZchZ	need_saver&   r&   r'   r  b  sX    



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 )N)z	task.epicztask.subprojectztask.gantt_projectz#parent_task.cache_branch_gantt_pathzparent_task.logic_prefixzODEV: WARNING: _calc_cache_branch_gantt_path: if cache_branch_gantt_path is NoneT)r4   )r,   r)   rk   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   ", которая уже является родительской для "r  )r   r   r  r  r  r>   r5   rF   r@   r,   r)   rk   )rO   r5   r  r&   r&   r'   r    s.    
z%CmfTask._calc_cache_branch_gantt_pathc             C   s   |s|  dg | j}g }| jr0dd | jD }| jsZ|rZ|jrZdd |jD |jjg }|rddd| gdd| gg}ddg}xRtjj||d	D ]>}|j	jj| jjkr|j	jjn|j
jj}||krtd
dd qW d S )Nz#parent_task.cache_branch_gantt_pathc             S   s   g | ]}|d  qS )r,   r&   )r   r  r&   r&   r'   r     s    z,CmfTask._check_relations.<locals>.<listcomp>c             S   s   g | ]}|d  qS )r,   r&   )r   r  r&   r&   r'   r     s    r9   r;   z==r:   )r<   rA   u   Невозможно перенести задачу из-за того, что они связаны связью ОН. Удалите связь и попробуйте снова.T)r4   )r>   r5   r  r  r,   rF   r-   rJ   r!   r:   r;   r@   )rO   r5   Z
gantt_pathr!  _fieldsrT   Zlink_idr&   r&   r'   r    s    &zCmfTask._check_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   
        Убирает метку дерева у родительской задачи при удалении или перемещении дочерних задач
        r  r5   r=   r,   z!=)r<   FT)r7   N)r>   r-   r
   r   r,   r  r  r3   )rO   r   Zhave_childrenr&   r&   r'   r    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
        Nzparent_task.has_child_taskszparent_task.op_gantt_taskT)r7   )r5   rp   r   r>   r  r  r3   rE   Z$task_has_child_tasks_is_changed_hookrx   r  )rO   r&   r&   r'   r}     s    
z)CmfTask._calc_parent_task_has_child_tasksc             C   s  | j jsd S d }| ddg | j r| j jr| j jjr| j jj}| j jj}|r|ddddddg | j| d	|j d
}t	j
| |dd  nt|jr| 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
| |dd  | j jr| 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 )Nz8responsible.primary_role.structural_project.default_listz0responsible.primary_role.structural_project_listr   r   ZordernoZperm_has_aclr   r   uU   SimpleLogic: Задача добавлена в структурный список "uG   " т.к. он указан в должности исполнителяrh   )r2   ri   rj   u>   SimpleLogic: Задача добавлена в список "u   " проекта "u   " т.к. он является Структурным проектом Главной роли ответственного по задачеz,primary_role.structural_project.default_listz$primary_role.structural_project_listuS   SimpleLogic: Задача убрана из структурного списка "uX   " т.к. он указан в должности прошлого исполнителяu<   SimpleLogic: Задача удалена из списка "u   " т.к. он является Структурным проектом Главной роли прошлого ответственного по задаче)r]   rp   r>   r   r   Zstructural_project_listrX   r^   rk   r-   rs   r3   rx  r2   rx   r	  )rO   Zappend_structural_project_listr   r  Zold_responsibleZremove_structural_project_listr&   r&   r'   r~    sZ    


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)
rq   r2   rp   r  rF   ro   r-   r   r>   Zdefault_agile_story_points)rO   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, когда существует базовый Гант-планT)r4   r  
const_work)r  rp   Zbp_gantt_taskr  r   r@   rE   r>   rx   r  r3   )rO   r&   r&   r'   ry  &  s    
zCmfTask._calc_estimate_workc             C   s   |  dg | jf |}tj }| jd |d |_| jjrV|jpHd| jjj	 |_d|j
_|  |jdd tj|d| j d| j dd	  |jj	S )
u    Создание задачи из шаблона
        :param self: Шаблон документа
        :param params: Параметры для шаблона
        :return: Идентификатор новой задачи
        ztmplt_document.textr   z%d.%m.%Yr6  T)r7   u0   Задача создана из шаблона rh   )r2   ri   rj   )r>   create_from_templater`   ra   rk   Zstrftimetmplt_documentr   ri   rF   r2   rp   r   r3   r-   rs   r)   r,   )rO   r  new_taskZnow_dater&   r&   r'   r   8  s    
$z!CmfTask.create_task_from_templatec                s&   | j dgd | jdkrdS t  S )uB    Шаблон уведомлений для разных workflow r   )rA   ztask.ticketzhelpdesk_mail_notification.html)r>   r   r    +get_default_mail_notification_template_name)rO   )r%   r&   r'   r  W  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 )Nr6  Zobj_result_textZobj_responsible_namesr   c             S   s   g | ]}t |jpd qS )r6  )rm  rk   )r   rr&   r&   r'   r   c  s    z-CmfTask.full_search_index.<locals>.<listcomp>)r>   Zfull_search_fieldsr-   ZCmfFullSearchZ
strip_htmlresult_textrF   r]   rk   rB  rQ  r    full_search_index)rO   r$   )r%   r&   r'   r  ^  s
    &zCmfTask.full_search_index   Добавленоc             C   s   |d krt j}tjj| |||||d}| jd|d |s<d S |jj}|d }||d  d }	||d  |	d  }
|r~| dnd}|	r|	 dnd}	|
r|
 d	nd}
d
||	|
f}tj	| d| dd
  |S )N)Z
start_daterw   zwork-logged)r[  i  <   u   дr6  u   чu   мr   u@   Добавлена запись в журнал работ на rh   )r2   ri   rj   )ry   rz   r-   r   Ztimetracker_task_change_timer   r  rF   rB  rs   r3   )rO   r  r  ri   Zdaterw   r[  Ztdr   ZhoursZminutesZ	timespentr&   r&   r'   r   g  s*    
zCmfTask.timetracker_change_timer'  )	only_oncer  rY   c             K   s   t j|  d S )N)r-   r
   _recalculate_codes)r   r  r&   r&   r'   recalculate_codes_celery  s    z CmfTask.recalculate_codes_celeryc             C   s|   d}d}xnt jjdd| gddg||| gdd}||7 }|s@d S x,|D ]$}|jsRqF|jdd |jdd	 qFW t  q
W d S )
Nr      r0   r=   r)   T)r<   rA   slicer6   )from_recalculate)r7   )r-   r
   r!   r0   
_calc_coder3   Zcommit_with_event)r   r   limitZ
task_slicer8   r&   r&   r'   r    s"    

zCmfTask._recalculate_codesc          	      sR  t  > tjj| d}|s*td dS td|  tjj|dgd}tdt|  dd	  t	| fd
dd}d}x|D ]}|d7 }td|  |rxtj
j|dD ]}|  qW |jjdd  d| }xPtj
jdd|gddr,td| d |d7 }|jjdd  d| }qW ||_|jdd qW W dQ R X dS )u  
            Метод для ручного запуска.
            Пересчитает номера в кодах задач начиная с единицы.
            ! Прошлые коды задач не сохраняются
            ! Пошлые коды задач удаляются
            Если код занят задачей из другого проекта - он пропусается
        )r,   u   Проект не найден!NuY   Удаляем историю выдачи кодов задачам из проекта r)   )r0   rA   u   Всего задач: c             S   s   yt | S    dS 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   rh   )r)   rF   
rpartition)r  )r  r&   r'   r8    r9  z<CmfTask.reindex_project_tasks_code_numbers.<locals>.<lambda>)r   r   r   u'   Обрабатываем задачу: )r8   r   r=   T)r<   r6   u   Код u    занят)r7   )rL  Zdisable_notifyr-   r   r   r  r
   r!   r   rA  r  rH   r)   rF   r  r   r3   )r   Zwith_history_deleter0   r  r   r8   ZhistZnew_coder&   )r  r'   "reindex_project_tasks_code_numbers  s0    	
 z*CmfTask.reindex_project_tasks_code_numbersr  )r  Zsoft_time_limitr  rY   c           	   K   s   t j}d}d}x|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 W td| d| d |S )u   Актуализация кеша кол-ва задач в епике (нужно ли для подпроекта? Вроде как нет).r   z	task.epicr  )r   rA   r   r5   r=   )r<   zUpdate cache_members_count z -> r   T)r7   )Znode_idZelements_countztree-node-count-changes-ztree-node-count-changesr  zRecalculate r  z lists caches)r-   r
   r!   r   r  ry   r   r,   r3   rF   Zcmf_emit_event
cmf_commit)r  r"   Ztotal_countZ
calc_countZcmf_epicZ
real_countZ
event_datar&   r&   r'   r    s$    
 

zCmfTask.recalculate_cache)	recursion)rr  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   r5   r   )r  r  )r   r>   r5   unionget_all_followersr    )rO   r  r#   r$   r  )r%   r&   r'   r    s    
zCmfTask.get_all_followersinline_save)tmp_objcreate_formui_form_moderA   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 )Nr\   r   zproject.ui_form_schemezproject.cust_field_conf_schemezproject.logic_prefixr  r.   request_typez,request_type.ui_form_view_inner.ui_form_jsonT)rA   r6   zproject.servicedeskr  )r  r  r  rA   )r  r  rA   )r   r0   r   r    r   r.   )r"   r  r  r  rA   r#   r$   )r%   r&   r'   r     s    
zCmfTask.ui_getc                s   t t|j}|p|j}|rn|jdkrn|r2|}n| j|jddgd}|jrn|jj	rnt
 j|||||jj	dS t
 j|||||dS )Nzproject.servicedeskr  z,request_type.ui_form_view_inner.ui_form_json)r,   rA   )r  tmp_is_public_formtmp_ui_view_formr  ui_form)r   Zget_cache_projectrm  r   r.   r   r   r,   r  Zui_form_view_innerr    _build_ui_form)r"   r  r  r  r  r  Ztmp_projectr*   )r%   r&   r'   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)r)   rA   cache_inmemory)r-   Z	CmfUiFormr   )rO   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)rk   r  r  r  r  c               s  |r,|s,t | j| jj|||||dd d S td| j d|  |rTd}d}d}| dddd	d
dddddg
 t j|	||d|
}|j	j
dd|_tjjddd}|r:dd|gg}x<tjj|dd| gg dgdD ]}| }||_|  qW x>tjj|dd| gg dgdD ]}| }||_|  qW | jsVtj| ||d  | || |rn||_d|_|  |rtjjdd| gd}x4|D ],}|j|jjd |||||||d d }qW |d!kr|j  tj| |S )"N)ru  rk   r  r  r  r  )r$   zcopy_task: task_id: z	, level: Tz**zattachments.urlr   rX   rQ  rP  zattachments.url_previewzattachments.url_preview_imgzop_gantt_task.actual_workr   )rk   r  r   )r   zsystem.clone)r)   r  relation_typez!=r:   z==)r<   rA   r;   )r:   r;   r  r5   )r<   u    Копияr   )rk   Zcopy_attachmentr  r  r  r   r  r  r   )ro  copy_task_with_subtasksr,   rF   ry   r   r>   r    r   r   r  r   r-   ZCmfRelationTyper   rJ   r!   cloner:   r3   r;   Zis_template_clone_op_gantt_taskr5   rq   r
   rk   rE   Ztask_copy_hookr  r  )rO   rk   r  r  r  r  r   r  r  r#   r$   new_objZ
clone_typer!  ZrelationZnew_relationZsubtasksrP   Znew_subtask)r%   r&   r'   r     sl    


zCmfTask.copyru  u!   Копирование задач)r  Zonly_once_argsdescriptionshow_bg_progressbarc             C   s<   t jjdd| gd}||  |j|||||dd d S )Nr,   z==)r<   T)rk   r  r  r  r  r   )r-   r
   r   r>   r?   r   )ru  rk   r  r  r  r  r8   r&   r&   r'   r  e  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 )Nz**r   z0.00T)r7   )rE   r>   r  r  Zactual_durationZactual_completeZactual_myself_workZactual_start_dateZactual_finish_dater   Zactual_costZactual_myself_costr8   r5   r3   )rO   r  r  r&   r&   r'   r  n  s    zCmfTask._clone_op_gantt_taskc                s2   |  dg | jdkr*d| j d| j S t jS )Nr   ztask.subprojectzproject/r  )r>   r   rH  r)   r    href)rO   )r%   r&   r'   r
  ~  s    
zCmfTask.hrefc       	      K   s   t t}d}d}xp| j|dddg|| |d | gd}x.|D ]&}x |jD ]}||j  d7  < qJW q>W t||k rvP |d7 }qW |S )Nr   i  z--r,   zlists.idr   )r<   rA   r  )r   r   r(   rX   r,   r   )	r"   r<   r  r  ZpageZ	page_sizer  r8   rs  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_prefixz'project.task_code_use_logic_type_prefixzlogic_type.obj_code_prefixtask_code_use_logic_type_prefixtask_code_prefixr   )
r   Zcode_prefixr>   r0   r\   Zobj_code_prefixr   r  r  rF   )rO   r&   r&   r'   get_code_prefix  s    zCmfTask.get_code_prefixc          
      s   t   }dd l}| }d}d}xtjjdd|gddr|d7 }t   }||k sltd| d	| j d
| | }|dkr$td|dd| j d| j	 dd| j
ko| j d	 q$W |S )Nr   i'  r)   r=   T)r<   r6   r   u8   Превышен лимит поиска кода limit=z model=uA   , возможно надо отключить def gen_code: passz$!!! --- gen_code::duration too long z.1fz sec, r   z, r   )r    gen_codetimer-   r  r   AssertionErrorr   r  r,   rA   r)   )rO   r)   r  startr  r   Zduration)r%   r&   r'   r    s    

 6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)   r8   r0   Tz'project.task_code_use_logic_type_prefix)r)   r0   rp   r\   r    r  r   rx   r  rF   r   r-   r  r   r3   rq   r>   r  r   )rO   r  r0   Zproject_oldZ
new_prefixZ	prev_codeZcode_history)r%   r&   r'   r    sb    
,
$



zCmfTask._calc_code)rA   r<   c         	   O   sj   |sg }|sg }| j |||d|}g }x:|D ]2}y|  || W q0 tk
r`   w0Y q0X q0W |S )N)rA   r<   )r!   Z_acl_check_readr^   ZCmfPermissionError)r"   rA   r<   r#   r$   Zres_uncheckedr  r  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   )rO   r$   )r%   r&   r'   r   "  s    zCmfTask.all_relation_personsc             C   s<   | j j  | j jj}| | jj|  | | jj| d S )N)rE   r  r   rF   #_update_actual_work_for_all_parentsr5   rx   r   )rO   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)rE   r   r  r3   )rO   r8   r  r&   r&   r'   r  0  s    
z+CmfTask._update_actual_work_for_all_parentsz@hourly)r  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} xtjj| dddddddddddddgdD ]b}|j	r|
 }t d|  |jjr|jj|_|jjdd|_|j  |j|_d |_d |_|  |  |jd
d qxt d|  |jdkrx@|jjdkrV|jj}|  |jr|j|jkr||_qW |jjrl|jj|_|jr|jjdd|_|jjdd|_|  qx|jjd krx|jjdd|_|jjdk r|j  |  qxW d S )!Nz(Run CmfPerson.cron_celery_check_periodicr9   zstatus.codez!=r   r   r   period_create_newr=   Tperiod_intervalperiod_next_datez<=)r[   zlists.ordernor   r   period_clear_checkboxri   ztmplt_document.textrZ   r_   )r<   rA   z6CmfPerson.cron_celery_check_periodic: create new task )r   )r7   z2CmfPerson.cron_celery_check_periodic: reopen task )r   r   r   ztox-checklist--checkedr6  pause)ry   r   r`   ra   rb   rc   r-   r
   r!   r  r  r  r   ri   r   r  r   r_   rd   rZ   r  r  r3   Z_cacl_next_periodr   r  rF   r  r2  r)   )r!  r8   r  Zold_deadliner&   r&   r'   cron_celery_check_periodic;  sT    







z"CmfTask.cron_celery_check_periodicc                sJ   |    |   |   |   |   |   |   t j|| d S )N)	r   r|   r}   r~   r   rN  r~  r    _save_import)rO   r#   r$   )r%   r&   r'   r    s    zCmfTask._save_importc                s*   t  |}|s&|tjdddg7 }|S )Nr  r;   r:   )r    import_shop_fieldsr-   rJ   )r"   Zfields_namer  )r%   r&   r'   r    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'g'}x(t jj D ]}|d(rd|| qdW t |||S ))Nr,   r)   rk   ri   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.loginz	tags.namezattachments.namezactivity.namez
lists.namezgit_repos.namezgit_branches.namezgit_merge_requests.namezgit_commits.namezrequest_type.namezop_gantt_task.actual_start_datez op_gantt_task.actual_finish_datezop_gantt_task.actual_durationzop_gantt_task.sched_durationzop_gantt_task.sched_start_datezop_gantt_task.sched_finish_datezop_gantt_task.sched_workzop_gantt_task.perform_workzop_gantt_task.actual_workZcf_)r-   r
   rA   keysr   r^   r    export2file)r"   rA   ZbqlZformat_filerQ   )r%   r&   r'   r    s"    
zCmfTask.export2file)id_listrA   c             C   s`   g }x4| j dd|gdgdD ]}||jj|dj qW |r\|| jdd |D |d |S )Nr,   ri  z--)r<   rA   )rA   c             S   s   g | ]
}|j qS r&   )r,   )r   r*   r&   r&   r'   r     s    z8CmfTask.group_changes_list_recursive.<locals>.<listcomp>)r!   r?  r   r   rF   r   )r"   r   rA   Zchildrenr8   r&   r&   r'   r     s    z$CmfTask.group_changes_list_recursive)	subgroupsrr  c             C   sv   xp|D ]h}| |d |d |d |d d}|  |}t |d< x.|d  D ]\}}|drL||d |< qLW qW |S )Nr   logic_type_idr   )r0   r2   r\   r   Zrequired_fieldsZ	ui_fieldsrequired)r  r  rn   r   )r"   r!  subgroupr  r  rQ   metar&   r&   r'   r     s    



z%CmfTask.group_changes_required_fieldsc             C   sn   xh|D ]`}| |d |d |d |d d}t j||d< |d ||d< t jj|d jjd|d< qW |S )	Nr   r"  r   )r0   r2   r\   r   r  r   )Zworkflow_idZstatus_list)r-   ZCmfSchemeWfZcalc_schemer  ZCmfWorkflowZget_status_listr,   rF   )r"   r!  r$  r  r&   r&   r'   r     s    
zCmfTask.group_changes_statuses)	operationr!  c             C   s(   t d t| j||tjjjdd d S )Nup   Обработка задач займет несколько минут, ожидайте оповещения.)r&  r!  notify_person_id)r$   )r@   ro  _group_changes_jobry   r   r,   rF   )r"   r&  r!  r&   r&   r'   r     s    zCmfTask.group_changesc             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  rp   rF   )rO   r)  r&   r&   r'   r     s    zCmfTask._clean_result_textu.   Массовое изменение задач)r  r	  )r&  r!  r'  c             C   s  dd l }d}d}x|D ]z}d}tjjdd|d gd}d }	|d	rT|d	  }	g }
x8td||| D ]}xtjjdd|d g|| || | g|	d
D ]}y| dkrx$|d	 	 D ]\}}t
||| qW |  nP| dkr"x(|d	 	 D ]\}}t||| qW |  n| dkr4|  |j  W q   |j  |
d|j d|j d|j d td|  Y qX qW qpW qW |
rd}dd|
 }tjj|||ddd d S )Nr   uW   Успешное завершение массового изменения задач.uZ   Массовое изменение задач закончилось без ошибок.r  r,   ri  r   )r<   Zchanges)r<   r  rA   updater^   rH   z	<a href="z">z (z)</a>u6   Не удалось обработать задачу uC   Ошибки при массовом изменения задач.u^   Обнаружены ошибки при изменении следующих задач</br>z</br>Tr   )r"  rk   msgZforce_notify_current_personrY   )mathr-   r
   r   r   r  rangeZceilr!   rn   rD   r3   r  r^   rH   rG   ZcommitZrollbackr
  rk   r)   loggingZ	exceptionrB  rW  Zplace_notify)r&  r!  r'  r,  Znotify_nameZ
notify_msgr$  stepZcntrA   Zerror_task_hrefsr   r*   Z	fieldnamerF   r&   r&   r'   r(    sN    





$"zCmfTask._group_changes_jobc             C   sN   | j rJ| jsJ| jrJ| jj}x.|D ]&}|jdks |jdkr:q | j| q W dS )ux   Устанавливаем для dummy task теже спринты, что и у родительской задачиzlist.agile_sprintr   N)rq   rX   r5   r   r   r^   )rO   Zparent_task_listsZparent_listr&   r&   r'   r     s    
z#CmfTask._set_lists_from_parent_task)ru  rv  rw  rr  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}xtd|   g }t jjddgdd|gd	}	d
}
x|	D ]}|j|krt	d|j  q|
|j |
d7 }
d}x&|D ]}||jkr|j| d}qW x&|D ]}||jkr|j| d}qW |sq|jdd |
d d
kr4t  |jr|| qW t  |}|sJP qJW dS )u  Синхронизация изменённых спринтов у подзадач

        Args:
            task_id (str): ИД родительской задачи, у которой поменялся lists
            sprints_to_add_ids (list): ИД спринтов для добавления в lists
            sprints_to_remove_ids (list): ИД спринтов для удаления из lists
        rX   )rA   r,   ri  )r<   z)deferred_job(_sync_subtask_sprints) task:r  r5   )rA   r<   r   zjob FAIL RESURSION r   FT)rq  r   N)r-   r
   r   r  r!   r   r.  infor,   errorr   rX   r^   r	  r3   r  r  )ru  rv  rw  r8   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{    sJ    






zCmfTask._sync_subtask_sprints)NN)F)F)F)F)F)NNN)r  NN)N)NNNNN)NNNNN)NNNN)NNNN)NNNN)NNNN)NNNN)NNNNNN)N)r   )N)N)r  NN)F)FNFN)N)F)N)NNr  )N)__name__
__module____qualname__modulesr8   rA   cmf_taskr
   Zapi_methodsservicedeskr-   CmfTaskMixinclassmethodr!   r   r(   r   r   rf   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   r  r  r#  r1  r.  r4  r   r5  r   rI  r   rN  rR  rV  rX  rZ  r?   r_  rc  rd  re  r   rh  recompileASCIIrj  rl  r   rp  r3   r   r  r  r  r  rH   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  r  r  r}   r~  r}  ry  r   r  r  r   r  r  r  r  r   r  r   r  r  rm  boolr   r  r  propertyr
  r   r  r  r  r   r   r  r  r  r  r  r  r   r  r   r   r   r   r(  r   r{  __classcell__r&   r&   )r%   r'   r
      s  , )4
%$*A1*
	A2  #G
 (%%*J9	t5   $;
   )0 9
	," "
0F&K L

+	r
   )r`   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_taskr5  Z#modules.servicedesk.models.cmf_taskZcommon.models.cmf_active_entityr	   r7  r-   r6  r8  r8   rA   r
   r&   r&   r&   r'   <module>   s   