U
    h;                    @   s   d dl Zd dlmZ d dlmZmZmZ d dlm	Z	m
Z
 d dlmZmZmZ d dlZd dlT d dlT d dlmZ G dd	 d	eZdS )
    N)tzutc)ROUND_UP
ROUND_DOWNROUND_HALF_UP)defaultdict
namedtuple)	bindparamfuncand_)*)CmfGanttTaskc                       s  e Zd ZdZejddg Zedd ZedddZd	d
 Z	dd Z
dd Zg ddfddZ fddZedd Zedd Zedd Zedd Zedd ZdddZdd d!Zd"d# Zd$d% Zd&d' Zdd(d)Zd*d+ Zdd,d-Zdd.d/Zdd0d1Zd2d3 Zd4d5 Zdd6d7Z d8d9 Z!d:d; Z"d<d= Z#d>d? Z$d@dA Z%dBdC Z&dDdE Z'dFdG Z(e)e*ddHgdIdJdKdL Z+ddMdNZ,ddOdPZ-dQdR Z.dSdT Z/dUdV Z0ddWdXZ1dYdZ Z2dd[d\Z3d]d^ Z4d_d` Z5ddadbZ6dcdd Z7d dedfZ8dgdh Z9didj Z:dkdl Z;dmdn Z<dodp Z=dqdr Z>dsdt Z?dudv Z@dwdx ZAddydzZBdd{d|ZCd}d~ ZDdd ZEdd ZFdddZGe)e*ddddgdIddddZHdddZIdddZJdd ZKdd ZLdddZMdd ZNdd ZOdd ZPdd ZQdd ZRdd ZSdd ZTdd ZUdd ZVdd ZWdd ZXdd ZYdd ZZdd Z[dddZ\dd Z]dd Z^dd Z_d	ddZ`d
ddZadddZbdddd fdd
Zc fddÄZddddĜ fddƄ
Ze fddȄZf fddʄZg fdd̄ZhdddτZiddф Zjddӄ ZkddՄ Zlddׄ ZmdddلZnddۄ Zoeddd݄Zpe)e*ddIdߍdd Zqe)e*ddIdߍdddZre)dd Zse)e*ddgdIddddd Zte)e*ddIdߍdddZue)dddZve)dd Zw  ZxS (  r   Toutline_insert_aftercalc_critical_pathc                 C   s   t  }ddddddddd	d
dddddg}t jjd ||d}|rV|D ]}|| ||< qD||_|  t  |jdddd W 5 Q R X |S )Nsched_start_datesched_finish_datesched_duration
sched_cost
sched_workconstrain_start_typeconstrain_start_dateconstrain_finish_typeconstrain_finish_dateprojectgantt_projecttaskparent_taskactual_start_dateactual_finish_date)parentr   fieldsFT)emitnotify	only_data)modelsr   getr   fix_null_variablescmfutildisable_notifysave)clsr   baseline
gantt_taskr   op_gantt_taskfield r.   (./modules/gantt/models/cmf_gantt_task.py_create_gantt_task_for_baseline   s.            
z,CmfGanttTask._create_gantt_task_for_baselineNc              	   C   s~   t  }|r| ||S |j  |j|_||_|j|_|j|_|  |	  |j
|_
t  |jddd W 5 Q R X |S )NF)r    r!   )r#   r   r0   r   loadr   	cmf_ownerZ
cmf_author
_calc_type_calc_projectr   r&   r'   r(   )r)   r   r*   r+   r.   r.   r/   create_gantt_task&   s    

zCmfGanttTask.create_gantt_taskc                 C   sp   | j rf| j jrft| j jj}|dkr,d| _|dkr:d| _|dkrHd| _|dkrVd| _|d	krld
| _nd| _d S )Nignore4-ignoreconst_duration0-const_durationZconst_resource2-const_resource
const_work1-const_workZconst_duration_and_work3-const_duration_and_work)r   
project_idAPPget_cache_projectZdefault_gantt_task_typetask_sched_type)selfZdefault_typer.   r.   r/   r3   C   s    zCmfGanttTask._calc_typec                 C   s   | j r| j jr| j j| _d S N)r   r   rB   r.   r.   r/   r4   S   s    zCmfGanttTask._calc_projectc                 C   s    | j r| j jS | jr| jjS d S rC   )r   r,   r   rD   r.   r.   r/   _get_parent_gantt_taskX   s    z#CmfGanttTask._get_parent_gantt_taskFc                 C   s   |d kr|   }| jjdkrPtjjddd gdd| jgdd| jgg|g |d}n*tjjdd| jgdd| jgg|g |d}|rtjjdddgd	d| jggd
gd}|rdd |D }tjjdd|gg|g |d}|	| |S )Ntask.gantt_projectr   ==r   r   filterr   relation_type.codesystem.additional_parentin_linkzout_link.op_gantt_task_idc                 S   s   g | ]}|j jqS r.   )out_linkop_gantt_task_id.0relr.   r.   r/   
<listcomp>y   s     z:CmfGanttTask._get_children_gantt_tasks.<locals>.<listcomp>idIN)
save_preload_fieldsr   logic_prefixr#   r   listr   CmfRelationOptionslistextend)rB   
add_filterr   include_additionalZchild_gantt_tasksZ additional_child_tasks_relationsZadditional_gantt_task_idsZadditional_gantt_tasksr.   r.   r/   _get_children_gantt_tasks^   s:    

	


z&CmfGanttTask._get_children_gantt_tasksc                    s8   ddddddddd	d
dddddddddg}t   | S )Nr   r   r   r   zgantt_project.op_gantt_taskr   zparent_task.gantt_projectparent_task.op_gantt_taskz(parent_task.op_gantt_task.outline_numbertask.logic_prefixztask.parent_task.logic_prefixtask.has_child_tasksztask.plan_start_dateztask.plan_end_dateztask.responsibleztask.executorstask.parent_taskztask.is_milestone task.gantt_project.op_gantt_task)superrU   )rB   r   	__class__r.   r/   rU      s*    z CmfGanttTask.save_preload_fieldsc                 C   s2   | j jrd S | j | j d }t|jtdtdS )Nd   z1.11Zrounding)r   is_null_perform_completeDecimalquantizer   rB   resr.   r.   r/   _perform_cost   s    zCmfGanttTask._perform_costc                 C   s:   | j jrd S | j | j d }t|jtdtd}t|S Nrf   1rg   )r   rh   ri   rj   rk   r   intrl   r.   r.   r/   _perform_duration   s
    zCmfGanttTask._perform_durationc                 C   s:   | j jrd S | j | j d }t|jtdtd}t|S ro   )r   rh   ri   rj   rk   r   rq   rl   r.   r.   r/   _perform_work   s
    zCmfGanttTask._perform_workc                 C   s   | j js| jjrdS |  }ttjt|jp.dd}tj	|}| j |krRdS |
| j j| jj}t|dkr|
| j j|}|| d }nd}|dkrd}t|jtdtd}t|S )Nr   Zsecondsrf   rp   rg   )r   rh   r   _get_calendardttimezone	timedeltarq   datetimenowZget_work_timedeltavaluerj   rk   r   )rB   calendarZtzrz   Zdelta_finish_time_secZdelta_now_time_secZperform_completerm   r.   r.   r/   ri      s$    
zCmfGanttTask._perform_completec                 C   sR   | j jrdS | j jdkrNddd gdd| j gdd| jgg}tjj|d}|rNdS dS )	NTrF   r   rG   r   r   rI   F)r   has_child_tasksrV   r   r#   r   sget)rB   _filterZhas_childrenr.   r.   r/   r~      s    

zCmfGanttTask.has_child_tasksc                 C   s   |sd S d}|}| j dkr*| jr*d}d}n| jrd}| jj}| jdkrd||krdd}|}d|d}nN| jdkr||krd}|}d	|d}n&| jd
kr||k rd}|}d|d}d| d|d}|r|sd| jj d| jj d| d}t|dd |S )NF0-constTu   невозможно изменить дату начала, если зафиксированы дата окончания и длительность (   Фиксированное начало %d.%m.%Y3-after   Начало не раньше 4-before   Начало не позже    ограничение "uE   " конфликтует с плановой датой начала <   Конфликт планирования: В задаче "" () .abort)	r   r8   r   r{   r   r   namecode	cmf_alertrB   estimated_datereturn_correct_dateZalertZcorrect_datetext
constraintZconstrain_dater.   r.   r/   check_correct_start_date   s6     z%CmfGanttTask.check_correct_start_datec                 C   s   |sd S d}|}| j dkr*| jr*d}d}n| jrd}| jj}| jdkrd||krdd}|}d|d}nN| jdkr||krd}|}d	|d}n&| jd
kr||k rd}|}d|d}d| d|d}|r|sd| jj d| jj d| d}t|dd |S )NFr   Tu   невозможно изменить дату окончания, если зафиксированы дата начала и длительностьr   .   Фиксированное окончание r   1-after%   Окончание не раньше 2-before#   Окончание не позже r   uK   " конфликтует с плановой датой окончания r   r   r   r   r   )	r   r8   r   r{   r   r   r   r   r   r   r.   r.   r/   check_correct_finish_date  s6     z&CmfGanttTask.check_correct_finish_datec                 C   s   d\}}}|   rB| jjdkrB|   }||   | \}}}|}| jdkrr| j}|rj|rjt||}n|pp|}|}| j	dkr| j
}|r|rt||}n|p|}d}| jr| j}n|}|||fS )u  
        Получает из родительской задачи ограничения
        по дате начала, дате окончания и максимальной длительности.

        Returns:
            start_limit: Defaults to None
                левая граница, за которую нельзя уйти влево (_plan_start_limit_min)
            finish_limit: Defaults to None
                правая граница, за которую нельзя уйти вправо (_plan_finish_limit_max)
            duration_limit: Defaults to None
                лимит длительности, нельзя превысить (_plan_duration_limit_max)
        NNNrF   r   r   r   r   N)rE   r   rV   load_fieldsrU   get_parent_plan_limitr   r   maxr   r   minr8   r   )rB   Zparent_start_limitZparent_finish_limitZparent_duration_limitparent_gantt_taskstart_limitfinish_limitduration_limitr.   r.   r/   r   /  s,    


z"CmfGanttTask.get_parent_plan_limitc           
      C   s<  d } }}| j sdS |  D ]}|jdkrP|s<|jj}n|jrPt||jj}|jdkr|s|jj}|jr|jrt	j
| |jjt|j }|}nD|jrt||jj}|jrt	j
| |jjt|j }t||}|jdkr|s|jj}n|jrt||jj}|jdkr|sZ|jj}|jr|jrt	j
| |jjt|j}|}nF|jrt||jj}|jrt	j
| |jjt|j}t||}|jr|s|j}n|jrt||j}|j r| \}}}	|s|}n|rt||}|s|}n|rt||}|s"|	}q|	rt||	}q|||fS )u~  
        !!! Очень тяжелый метод

        Получает из дочерних задач ограничения
        по дате начала, дате окончания и максимальной длительности.

        Returns:
            start_limit: Defaults to None
                левая граница, за которую нельзя уйти вправо (_plan_start_limit_max)
            finish_limit: Defaults to None
                правая граница, за которую нельзя уйти влево (_plan_finish_limit_min)
            duration_limit: Defaults to None
                самая большая фикс. длительность или фикс. трудозатраты (пока нет поддержки ресурсов),
                нельзя меньше (_plan_duration_limit_min)
        Nr   )r   r   r   )r   r   r   )r~   r]   r   r   r{   r   r   r   r   r#   CmfCalendarget_date_by_durationru   rq   r   r8   get_childrens_plan_limit)
rB   r   r   r   r+   r   r   Zch_start_limitZch_finish_limitZch_duration_limitr.   r.   r/   r   Z  s    









z%CmfGanttTask.get_childrens_plan_limitc                 C   sB   t | ddrd S d| _|  \| _| _| _|  \| _| _| _	d S )N_calc_plan_limits_cache_doneFT)
getattrr   r   _plan_start_limit_min_plan_finish_limit_maxZ_plan_duration_limit_maxr   _plan_start_limit_max_plan_finish_limit_minZ_plan_duration_limit_minrD   r.   r.   r/   _calc_plan_limits_cache  s    z$CmfGanttTask._calc_plan_limits_cachec                 C   sn   | j r<| jr<tjj|  | j j| jj| jjp.|d}|| _n| j j	rR| jj	rRd| _| jj
rj| jd||d d S )N)r|   from_dtto_dtforce_include_endsr   T)from_calc_sched_durationfrom_child_changesfrom_sched_dates_changed)r   r   r#   r   get_duration_minutesru   r{   	is_manualr   old
is_changed_do_sched_duration_is_changed)rB   r   r   r   Zcalendar_durationr.   r.   r/   _calc_sched_duration  s    
z!CmfGanttTask._calc_sched_durationc                 C   sF   | j r,| jr,tj|  | j j| jj| _n| j jrB| jjrBd| _d S Nr   )	r   r   r#   r   r   ru   r{   actual_durationr   rD   r.   r.   r/   _calc_actual_duration  s      z"CmfGanttTask._calc_actual_durationc                 C   sR   t j|  | jjt| j }| j||d}| j	dkrN| j
rN| j
|krN| j
}|S )u  
        Расчитывает дату начала.
        При возникновении конфликтов ограничений, откатывает на дату ограничения при rollback=True

        Args:
            rollback (bool, optional): Defaults to False
                при конфликте откатить на дату ограничения

        Returns:
            sched_start_date:
                плановая дата начала
        r   r   r   )r#   r   r   ru   r   r{   rq   r   r   r   r   )rB   rollbackr   r   r.   r.   r/   _calc_sched_start_date  s      

z#CmfGanttTask._calc_sched_start_datec                 C   s0   t j|  | jjt| j}| j||d}|S )u  
        Расчитывает дату окончания.
        При возникновении конфликтов ограничений, откатывает на дату ограничения при rollback=True

        Args:
            rollback (bool, optional): Defaults to False
                при конфликте откатить на дату ограничения

        Returns:
            sched_finish_date:
                плановая дата окончания
        r   )	r#   r   r   ru   r   r{   rq   r   r   )rB   r   r   r   r.   r.   r/   _calc_sched_finish_date  s      z$CmfGanttTask._calc_sched_finish_datec                 C   s   | j js| j dkrD| jjs"d | _n| jr2| j| _n| jr@| j| _d S | jjrX| jjrXd S | jr| js| j|d| _|r~d | _nd S | jr| js|  | _| jdkr|  | _d S | j	dkr| jdkr| j
rtd d S )Nr   r   r   r   u   Плановый период может не соответствовать плановой длительности, т.к. все переменные зафиксированы)r   rh   r   is_milestoner   r   r   r   r   r   r8   r   )rB   r   r.   r.   r/   _calc_sched_period  s,    



zCmfGanttTask._calc_sched_periodc                 C   s   | j js| j dkrd | _d S | jjr0| jjr0d S | jrZtj|  | jjt	| j | _d S | jrtj|  | jjt	| j  | _d S d S r   )
r   rh   r   r   r#   r   r   ru   r{   rq   rD   r.   r.   r/   _calc_actual_periodF  s&        
z CmfGanttTask._calc_actual_periodc                 C   s   | j dkrf| jjr| jjr| jdkrt| j| j d }t|d}| jjsV|| jkr|| _| 	  nd| j dkr| jjr| j
jr| j
dkrt| j| j
 d }t|d}| jjs|| jkr|| _| 	  dS )uR   
        Вычисляет фактический % завершения
        0-workr   rf   5-timetrackerN)actual_complete_typeactual_workis_not_nullr   mathfloorr   actual_completerh   $notify_parent_update_actual_completetimetracker_sched_work)rB   tmp_completer.   r.   r/   _calc_actual_completeZ  s    




z"CmfGanttTask._calc_actual_completec           
      C   s  | j s
dS | jdkrdS | jdkr&dS | jdkr| jdgd}|sFdS t|}d}|D ]6}|r||j|jkr|||jjpvd7 }qV||jjpd7 }qV|| }n:| jdkr| jjd	krt	j
jd
ddgdd| jggddgd}nt	j
jd
d| jgddgd}|s dS d}d}	|D ]}|rp|j|jjkrp|jddg ||jjjpFd7 }|jjjdkr|	|jjjpjd7 }	n2||jjp~d7 }|jjdkr|	|jjpd7 }	q|	| d }n | jdkrdS | jdkrdS | j|k r|| _dS )uB   
        updated_ch_gantt_task - указан, когда
        Nr   r   
1-completer   )r   r   2-story_pointsrF   r   rG   r   agile_story_pointszstatus.status_typerH   =CLOSEDrf   3-costz4-fixed)r~   r   r]   lenrS   r   r{   r   rV   r#   CmfTaskrW   r   r   statusstatus_type)
rB   updated_ch_gantt_taskZch_gantt_task_listZtotal_countZsum_actual_completecZres_actual_completeZch_task_listZtotal_story_pointsZfinished_story_pointsr.   r.   r/   _calc_summarry_actual_completeo  s`    



z+CmfGanttTask._calc_summarry_actual_completec           
      C   sv  |    | jdkr(| js.| jr.| j| _nd | _| jdkrD| j| _n| jdkr| j}| jrn| jrnt| j| j}|r| jr| j|k r|| _n`| jdkr| j}| jr| jrt| j| j}|r| jr| j|kr|| _n| jdkrtj	j
dd| jgdd	d
gd}d }d }|D ]V}|jjjj}|rD|jrD|jjj}tj|||j}|r
|rZt||n|}q
d }|  }|r|j }	|	r|	}n| jr| j}|r|rt||| _n|s|r|p|| _n | jr| j| _| jr| j| _| jr| jr| j| jkrtddd | jr@| jr@| j| jk r@tddd | jdk| _| jrf| jjrf|   | jdd d S )N)r   r   r   r   r   r   1-earlyrL   rG   z(out_link.op_gantt_task.sched_finish_dateconstrain_lagz"out_link.project.calendar.timezonerH   u~   Нельзя указать Дату начала больше зафиксированной у дочерней задачиTr   u   Нельзя указать Дату начала меньше зафиксированной у родительской задачиr"   )r   r   r   r   r   r   r   r   r#   rX   rW   r   rM   r,   r   r{   r   r   r|   r   r   rE   r1   r   lock_sched_start_dater   _do_sched_start_date_is_changedr(   )
rB   r   Zin_relationsZmax_prev_dater|   Zin_relationfinish_dateZnew_sched_start_dater   parent_sched_start_dater.   r.   r/   #_do_constrain_start_date_is_changed  sr    









z0CmfGanttTask._do_constrain_start_date_is_changedc                 C   s   g }| j jdkrd S |  r<|  }||   || dd| j gdddgg}tjj|dgd}|rdd	 |D }d
d| j	gdd|gg}tj
j||  d}|| |S )NrF   rM   r   rJ   rK   rL   rH   c                 S   s   g | ]}|j jjqS r.   )rL   r{   rS   rO   r.   r.   r/   rR   $  s     z8CmfGanttTask._get_parent_gantt_tasks.<locals>.<listcomp>r   task_idrT   )r   rV   rE   r   rU   appendr#   rX   rW   r   r   rZ   )rB   parent_gantt_tasksr   r   Zadditional_parents_relationsZadditional_parents_tasks_idsZadditional_parents_filterZadditional_parentsr.   r.   r/   _get_parent_gantt_tasks  s.    



z$CmfGanttTask._get_parent_gantt_tasksc                 C   s.   d }| j rt| j j}|p,tjjddgdS )Nsystem:defaultrw   r   r   )r>   r?   r@   r|   r#   r   r$   )rB   r|   r.   r.   r/   ru   /  s    zCmfGanttTask._get_calendarc                 C   s6  d }d }dddg}| j |dd}|D ]}|j| jkr|  |j| jjdd|_d |_|jrf|	  n|j
dd |  |  |jdd |s|jj}nt||jj}|jr|s|jj}nt||jj}| j|d | j|d q$| jr| jr| jrd | _| 
  n$|r|| _|r&|| _| jdd	 d S )
Nr   !=Tr[   r\   r   r   r   r   )r   )r]   r   r   r   r   r   newr   r~   "_calc_sched_period_for_child_tasksr   _alert_changed_plan_fields_check_start_finish_relationsr(   r{   r   r   r   r   r   r   )rB   r   r   r[   child_tasks
child_taskr.   r.   r/   r   7  sF    




z/CmfGanttTask._calc_sched_period_for_child_tasksc                 C   s   | j | jjd |   | jrr| jjrr| jrh| j| jk rh| j| _td| jj d| jj	 d| jdd | 
  nJd }| jr| jr| jsd | _| jdd d	}n| jdd
 d}| j|d d S )Nr   u/   Предупреждение: В задаче "r   u2   ) дата начала перемещена на r   ub   , так как была позже даты ограничения дочерней задачи.Tr   
start_dater   durationchanged_field)r   r   r   r   r~   r   r   r   r   r   r   r   lock_sched_finish_dater   r   r   _calc_resourcesrB   r   r.   r.   r/   r   n  s    (
z,CmfGanttTask._do_sched_start_date_is_changedc                 C   sx   | j | jjd |   d }| jrR| jsR|   d}| jrb| jjrb| jrb| 	  n| j
dd d}| jst| j|d d S )Nr   r   Tr   r   r   )r   r   r   r   r   r   r   r~   r   r   r   r  r  r.   r.   r/    _do_sched_finish_date_is_changed  s    
z-CmfGanttTask._do_sched_finish_date_is_changedc                 C   sJ   | j | jjd | j| jjd | jdd | jr:|   | jdd d S )Nr   Tr   r   r   )	r   r   r   r   r   r   r~   r   r  rD   r.   r.   r/   _do_sched_dates_is_changed  s    z'CmfGanttTask._do_sched_dates_is_changedc                 C   s\   |j r| j r|j | j k s0|jrX| jrX|j| jkrXd}t||jj|jj| jj| jj d S )Nu   Задача "{}" ({}) вышла за диапазон плановых дат родительской задачи "{}" ({}))r   r   r   formatr   r   r   )rB   r   msgr.   r.   r/   %_alert_child_task_outside_sched_dates  s    

z2CmfGanttTask._alert_child_task_outside_sched_datesr      )	only_onceonly_once_argspriorityc                 C   s`   t jj| d}|sd S | }|| t jj||d}|s@d}|jd||d |jdd d S )NrS   rS   r   T)deferredr   ignore_child_taskr   )r#   r   r$   rU   r   from_sched_dates_of_child_tasksr(   )r   child_task_idr  r   r   r   r.   r.   r/   #from_sched_dates_of_child_tasks_job  s    
z0CmfGanttTask.from_sched_dates_of_child_tasks_jobc              
   C   s  |s2| j jdkr2t| j| jj|jj|dd dS | jrN|rJ|sJ| | dS |dkr\t }| jj|krtt	ddd |
| jj d}d}|s|nd}|s|nd}dd	d
dgdd
dgg}	| j|	dd}
|
D ]v}|r|j|jkrq|jr|s|}n|js|}n|j|jkr|}|jr|s"|}q|js0|}q|j|jk r|}q|rN|j}|rZ|j}|s|r|jr|js|j|k r|j}|s|r|jr|js|j|kr|j}d}d}| jr^|r^d|j j d|j j d}| jj}| jdkr||krd|d}nL| jdkr6||k r6d|d}n(| jdkrZ||krZd|d}nd}d}| jr|rd|j j d|j j d}| jj}| jdkr||krd|d}nL| jdkr||k rd|d}n(| jdkr||krd|d}nd}|r@|p|}t	d| j j d| j j d| d| d	dd || _|| _| jjs`| jjrn| jddd  |   |  }|rt D |D ]8}||   |j| |d! |  |jd"dd# qW 5 Q R X || jj dS )$u  
        Обновляет плановые даты родительской задачи.
        Плановая дата начала = самая ранняя плановая дата начала всех подзадач
        Плановая дата окончания = самая поздняя плановая дата окончания всех подзадач

        Args:
            child_task (optional): Defaults to None
                измененная дочерняя задача, которая еще не сохранена.
            ignore_child_task (bool, optional): Defaults to False
                игнорировать дочернюю задачу при обновлении дат родительской задачи.
        rF   )r   r  r  kwargsNu   Невозможно обновить даты из-за обнаруженного цикла обновления дат задач связями Дополнительный родитель/Дополнительная дочерняя задача.Tr   ORr   r   r   r   "r   )r   r   r   r   r   r   r   r   r   r   r   r   uU   Конфликт планирования: В родительской задаче "u   ) ограничение "u<   " конфликтует с дочерней задачей r   )r   r   )pathF
user_inputr"   ) r   rV   schedule_deferred_jobr  rS   r{   r   r  setr   addr]   r   r   r   r   r   r   r   r   r   r   r   r   r&   disable_aclr   rU   r  r   r(   remove)rB   r   r  r  r  Zmin_start_dateZmax_finish_datesZchild_task_with_min_startZchild_task_with_max_finishr[   gantt_tasksr+   r   Zconflict_child_task_min_startr   Zconflict_child_task_max_finishr   Zconflict_child_taskr   r   r.   r.   r/   r    s    

&
z,CmfGanttTask.from_sched_dates_of_child_tasksc              	   C   st   |   }|rpt V t }|| jj |D ]6}|jj|kr.|j| ||d |  |j	ddd q.W 5 Q R X dS )uq  
        Обновление дат начала и окончания родительской задачи и доп родительских задач.
        Передает дочернюю задачу (self), так как она еще не сохранена
        и родительская задача не может получить обновленные данные.

        Args:
            ignore_child_task (bool, optional): Defaults to False
                игнорировать дочернюю задачу при обновлении дат родительской задачи.
        )r  r  FTr  N)
r   r&   r  r  r  rS   r{   r  r   r(   )rB   r  r   r  r+   r.   r.   r/   update_parent_task_sched_datesY  s    

z+CmfGanttTask.update_parent_task_sched_datesc                 C   s   |   }|D ]}|jdkr$td q| | r|| rD| | || k r|jdkrt|| rt| | || krttd  d S |jdkr|| r| | || k rtd  d S | | ||< |  |j|d qd S )Nr   ^   Дата родительской задачи является зафиксированнойr   u   Предупреждение: Плановая дата начала дочерней задачи больше плановой даты начала родительской задачиr   u   Предупреждение: Плановая дата начала дочерней задачи меньше плановой даты начала родительской задачи)
date_field)r   r   r   r(   _change_parent_start_date)rB   r#  parentsr   r.   r.   r/   r$  s  s&    
 z&CmfGanttTask._change_parent_start_datec                 C   s   |   }|D ]}|jdkr$td q| | r|| rD| | || kr|jdkrt|| rt| | || k rttd  d S | | }|jdkr|| r| | || krtd |jr||jkr|j}|||< |  || q| jdk| _d S )Nr   r"  r   u   Предупреждение: Плановая дата окончания дочерней задачи меньше плановой даты окончания родительской задачиr   u   Предупреждение: Плановая дата окончания дочерней задачи больше плановой даты окончания родительской задачи)r   r   r   r   r(   _change_parent_finish_dater   r   )rB   r#  r%  r   Z
date_valuer.   r.   r/   r&    s,    
 z'CmfGanttTask._change_parent_finish_datec                 C   s  |    | jdkr(| js.| jr.| j| _nd | _| jdkrB| j| _n| jdkrx| j}| jrl| jrlt| j| j}|r|| _nb| jdkr| j}| jr| jrt| j| j}|r| jr| j|kr|| _n| jr| j| _| j	r| j	| _| jr&| j
r| j| j
krtddd | jr&| j| jk r&tddd | jdk| _| jrn| jjrn| jrf| jdkr`| jsfd | _|   | jr| jjr| jdkr| jsd | _|   | jdd	 d S )
N)r   r   r   r   r   r   u   Нельзя указать Дату окончания больше зафиксированной у родительской задачиTr   u   Нельзя указать Дату окончания меньше зафиксированной у дочерней задачиr   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r(   )rB   r   r.   r.   r/   $_do_constrain_finish_date_is_changed  sL    





z1CmfGanttTask._do_constrain_finish_date_is_changedc           	      C   s.  | o | j jo | j dko | jj }| o>| j j o>| j o>| jj}|oX| jj oX| j| jk}|sf|sf|r| jj | j_| jjdd | jdkr| jdkr| j	j
s| jj
s|rtddd ntddd | jrtd| jj d	| jj d
dd |s*|s| jrd | _| jdd |s*|s*| jdd d S )Nr   Tr   r   u  Конфликт планирования: невозможно изменить трудозатраты, если установлена опция "Фиксированные Ресурсы" и зафиксированы даты начала и окончания.r   u   Конфликт планирования: невозможно изменить длительность, если зафиксированы даты начала и окончания.ua   Невозможно изменить плановую длительность, у задачи  (uZ   ) установлена опция "Фиксированная длительность".r   r   r   )r   r   r   r   r   r   r(   r   r   r   r   r   r   r8   r   r   r   r  )	rB   from_sched_work_changedr   r   r   from_calc_resourcesZcase_aZcase_bZcase_cr.   r.   r/   r     s:    "z*CmfGanttTask._do_sched_duration_is_changedc                 C   s   |    d S rC   )r   rD   r.   r.   r/   _do_actual_duration_is_changed-  s    z+CmfGanttTask._do_actual_duration_is_changedc                 C   st  t d| jj d| jjj  | jjr,d S | jdk r\td| jj	j d| jjj ddd | j
}|rn|snd}|s| jjd	kr| j| _|   | jjpd| jjpd }t d
| jj d| jjj d| jjpd d| jjpd d| jj 
 |  rP| jjd	krPt > |  }||   || |jdd |jdd W 5 Q R X |sp| jjrptj| j| d S )Nz*_do_actual_work_is_changed start, gt_id : 
, t_code: r   u@   "Фактические трудозатраты" задачи "r   u   ) стали ниже нуля.Tr   rF   z"_do_actual_work_is_changed gt_id: z, gt.actual_work.new: z, gt.actual_work.old: z, work_delta: from_add_childr   )gdebugrS   r{   r   r   r   rh   r   r   r~   rV   actual_myself_workr   r   r   rE   r&   r  r   rU   from_child_add_work_do_actual_work_is_changedr(   r   r#   ZCmfTimeTrackerZ"_op_gantt_actual_work_changed_hook)rB   from_timetrackerr.  r~   
work_deltar   r.   r.   r/   r3  0  s,     
&F

z'CmfGanttTask._do_actual_work_is_changedc              	   C   s   | j jrd S | j dk r"tddd | jdkr~| jjr~| jdkr~t| j | j d }t|d}| j	jsp|| j	kr~|| _	| 
  |  r| jjdkr| j jpd| j jpd }t 2 |  }||   || |jdd	 W 5 Q R X d S )
Nr   ue   "Фактические Затраты" стал ниже нуля, выставляем в ноль.Tr   r   rf   rF   Fr  )actual_costrh   r   r   r   r   r   r   r   r   r   rE   r   rV   r   r   r&   r  r   rU   from_child_add_costr(   )rB   r   
cost_deltar   r.   r.   r/   _do_actual_cost_is_changedS  s$    




z'CmfGanttTask._do_actual_cost_is_changedc                 C   s,   | j jrd S | jdkrd S | jdkr(d S d S )Nr   r   )r   rh   r   rD   r.   r.   r/   _do_actual_complete_is_changedk  s    

z+CmfGanttTask._do_actual_complete_is_changedc                 C   sF   | j jp
d| j jpd }| js(| j | _n|  j|7  _| j|d d S )Nr   r4  )r1  r   r   r~   r   r3  )rB   r4  r5  r.   r.   r/   !_do_actual_myself_work_is_changed{  s
    
z.CmfGanttTask._do_actual_myself_work_is_changedc                 C   sB   | j jp
d| j jpd }| js(| j | _n|  j|7  _|   d S r   )actual_myself_costr   r   r~   r7  r:  rB   r9  r.   r.   r/   !_do_actual_myself_cost_is_changed  s
    
z.CmfGanttTask._do_actual_myself_cost_is_changedc           	   	   C   sT  | j jrd S | j| j kr(| j | _|   | jr| j | jk r| jd  d| jd  d}| j d  d| j d  d}| jrtd| d| ddd n| j| _ |std	| d
 |   | 	 r2| j
jdkr2| j jpd| j jpd }t < | 	 }||   || |  |jddd W 5 Q R X |sP|sP|sP| jdd d S )N<      ч    мu   Нельзя запланировать меньше Трудозатрат, чем запланировано в подзадачах ( < ub   ). Увеличьте Трудозатраты или уменьшите их у подзадач.Tr   u   Указано Трудозатрат меньше, чем запланировано в подзадачах. Выставили uo   . Если нужно уменьшить Трудозатраты, уменьшите их у подзадач.rF   r   Fr  workr   )r   rh   r   %_do_timetracker_sched_work_is_changedr~   agregat_workr;   r   r   rE   r   rV   r   r   r&   r  r   rU   from_child_agregate_workr   r(   r  )	rB   Zfrom_sched_duration_changedr   r   r*  rG  r   r5  r   r.   r.   r/   _do_sched_work_is_changed  s6    

z&CmfGanttTask._do_sched_work_is_changedc              	   C   s   | j jrd S | j | jk rX| jr>td| j  d| j ddd n| j| _ td| j d |  r| jjdkr| j jpvd	| j j	pd	 }t
 < |  }||   || |  |jd
dd W 5 Q R X d S )Nu   Нельзя запланировать меньше Расходов, чем запланировано в подзадачах (rD  uX   ). Увеличьте Расходы или уменьшите их у подзадач.Tr   u|   Указано Расходов меньше, чем запланировано в подзадачах. Выставили ue   . Если нужно уменьшить Расходы, уменьшите их у подзадач.rF   r   Fr  )r   rh   agregat_cost
const_costr   rE   r   rV   r   r   r&   r  r   rU   from_child_agregate_costr   r(   rB   r9  r   r.   r.   r/   _do_sched_cost_is_changed  s"    

z&CmfGanttTask._do_sched_cost_is_changedc                 C   s"   | j r| jr|   n|   d S rC   )r   r   r   r   rD   r.   r.   r/    _do_actual_start_date_is_changed  s    
z-CmfGanttTask._do_actual_start_date_is_changedc                 C   s(   | j s| jr| jr|   n|   d S rC   )r   r   r   r   r   rD   r.   r.   r/   !_do_actual_finish_date_is_changed  s    
z.CmfGanttTask._do_actual_finish_date_is_changedc                 C   sX   | j dkr|   n@| j dkr.| jr.|   n&| j dkrB|   n| j dkrT|   d S )Nr   r   r   r   r   )r   r3  r~   r   r:  rF  rD   r.   r.   r/   #_do_actual_complete_type_is_changed  s    





z0CmfGanttTask._do_actual_complete_type_is_changedc                 C   s   | j r|   d S rC   )r8   r   rD   r.   r.   r/   _do_const_duration_is_changed  s    z*CmfGanttTask._do_const_duration_is_changedc                 C   s\   | j r|   nHdddgdd| jgg}| js:tjj|drJ| jd dd nd| _| 	  d S )	NrJ   rG   rK   rL   r}   Tr   r  r   )
r   r   r   r~   r#   rX   r   r  r   r   )rB   Z_additional_task_filterr.   r.   r/   _do_is_manual_is_chagned  s    

z%CmfGanttTask._do_is_manual_is_chagnedc                 C   s"   | j jdkr| j r| jdd d S )Nr7   unitsr   )rA   r   r  rD   r.   r.   r/   _do_task_sched_type_is_changed  s    z+CmfGanttTask._do_task_sched_type_is_changedc                 C   s*   | j rd| _| j| _n| jj| _d | _d S Nr   )r   r   r   r   defaultrD   r.   r.   r/   $_do_lock_sched_start_date_is_changed  s
    

z1CmfGanttTask._do_lock_sched_start_date_is_changedc                 C   s*   | j rd| _| j| _n| jj| _d | _d S rX  )r   r   r   r   rY  rD   r.   r.   r/   %_do_lock_sched_finish_date_is_changed  s
    

z2CmfGanttTask._do_lock_sched_finish_date_is_changedc                 C   s   |sd S |  ddddg |j }| |   || j || j || j	 |
  || j |jdd |jr| js| j|jjdd| _| jjr|   ||  n|jr| jrn
||  |jdd d S )	Nr   r   r7  r   Tr-  r   r   )r   r,   r1   rU   rL  r   rH  r   r8  r7  r:  r2  r   r3  r   r   r   r{   r   r   r  r  r(   rB   r   r   r.   r.   r/   add_child_task_to_parent_task%  s.    

z*CmfGanttTask.add_child_task_to_parent_taskc                 C   s   |sd S |  ddddg td| jj d| jjj d| jj  |j	 }| | 
  || j  || j  || j  |  || j  |  |j| dd	 |jdd
 d S )Nr   r   r7  r   z*remove_child_task_from_parent_task gt_id: r,  z$, gt.actual_work to be substracted: T)r  r   )r   r/  r0  rS   r{   r   r   r   r,   r1   rU   rL  r   rH  r   r8  r7  r:  r2  r3  r  r(   r\  r.   r.   r/   "remove_child_task_from_parent_taskC  s    *
z/CmfGanttTask.remove_child_task_from_parent_taskc              	   C   sP   t  > | jjp| j}|r&| | | jjp2| j}|rB| | W 5 Q R X d S rC   )r&   r  r   r   r   r^  r   r]  )rB   Z
old_parentZ
new_parentr.   r.   r/   _do_parent_task_is_changedV  s    

z'CmfGanttTask._do_parent_task_is_changedc                 O   s   t jj| df|| d S )Nupdated)r#   ZCmfEventZdo_eventrB   argsr  r.   r.   r/   _do_event_savec  s    zCmfGanttTask._do_event_savec                 O   s
   | | j S rC   )Z	log_level)rB   
field_namerb  r  r.   r.   r/   _get_field_log_levelf  s    z!CmfGanttTask._get_field_log_levelc                 C   s  | j rDd| _d| _|  r@|  }|j }|| _d| _|   d S | jjrRd| _| j	j
rf|   d S | jj
rz|   d S | jj
r|   d S | jj
r|   |s|   d S | jj
r|   d S | jj
r|   d S | jj
r|   d S | jj
r|   d S | jj
r"|   |s|   d S | jj
r8|   d S | jj
rN|   d S | jj
rd|    d S | j!j
rz| "  d S | jj
r| #  |s|   d S | j$j
r| %  |s|   d S | j&j
s| jj
r| '  |s|   d S | j(j
s| j)j
r| *  |s|   d S | j+j
r4| ,  d S | j-j
rJ| .  d S | j/j
r`| 0  d S | j1j
rr| 2  | j3j
r| 4  | j5j
r| 6  |s|   d S )Nr   r   )7is_newr   r   rE   r   r1   r   r   rh   r   r   r_  r1  r=  r>  r@  r   r!  r   r+  r   r3  r7  r:  r   r;  rI  r   rN  r   rO  r   rP  r   rR  r   r   r  r   r   r   r   r'  r   rU  r8   rS  r   rZ  r   rF  r   r[  rA   rW  )rB   from_parent_changesr   r   r.   r.   r/   _savej  s    













zCmfGanttTask._saveuS   Вычисление плановых работ по ресурсам задачиgantt_task_id)descriptionshow_bg_progressbarr	  r
  r  c              
   C   s  t d|   | d krd S tjj| d}|s2d S ||  dd|jgdddgg}tjj	|dgdD ] }t
  |  W 5 Q R X qhtjj	dd|jgddd	gd}|sd S |jj}|jj}t|jj}t|jj}t|}	|| |	 }
|}d
}|	dkr||	 }||	 }t d|jjj d|   |D ]6}|}|d
krL||7 }d
}|j|||||
dd q.t d|  d|jjj  d S )Nz)calc_resources_job start. gantt_task_id: r  r   rG   history_typeplanrH   personr|   r   r  z4calc_resources_job start_res_assignment. task.code: z gantt_task_id: T)
assignment	work_leftr   r   rV  
create_tthz'calc_resources_job end. gantt_task_id: z task.code: )r/  r0  r#   r   r$   r   rU   r   CmfTimeTrackerHistoryrW   r&   r  deleteCmfTaskResAssignr   r{   r   rj   r   r   r   r   _plan_resource_days)ri  r+   r   tthassignmentsr   r   r   rE  number_of_resourcesrV  work_per_personwork_remainderro  rp  r.   r.   r/   calc_resources_job  sV    




zCmfGanttTask.calc_resources_jobc              
   C   s  d }d }	|j j| | jj|o$| d}
zt|
}W n2 tk
rh } ztt|dd W 5 d }~X Y nX |jj}d}|| krt	|
|}t	|jj| }|dkrq*t	|| jt	dtd}|| | }||8 }||k r|}|t|}|t||| |  p|jddd	}|rbtj|j| j||d
t|dd}t  |jdd W 5 Q R X |sl|}|d k	r||d}|| |kr|| ||< ||8 }t|jt	dtddkr*|}	qq*||	fS )N)r   r   r   Tr   r   rp   rg      ;   )hourminuterm  )r2   r   r   Zend_daterl  
time_spentremaining_estimateF)r!   )r|   Z	work_daysdater   r{   nextStopIterationr   strrj   Zget_work_time_shiftZinterval_total_minutesrk   r   Zget_shifted_work_timerq   replacer#   rr  rn  r   r&   r  r(   r$   r   )rB   ro  rp  r   r   rV  max_work_per_dayrq  
start_timeend_timeZdays_generatorZdayeZcur_dateZ
time_shiftZ
avail_timeZwork_for_todayZwork_for_today_remainderZtth_start_dateZtth_end_daterv  Zcur_max_work_for_todayr.   r.   r/   ru    s^    
"*	

z CmfGanttTask._plan_resource_daysc              
      s<   fdd}|sd S j dkr$d S tdj  ddjgdddgg}ttjj|d	gd
dk}|stjj	|dgd
D ] }t
  |  W 5 Q R X q|jj}jj}tjj}	tjj}
|
}|	}d}|d krtjj	ddjgdddgd
}t| | }|
sPjjrP|sPjs0j dkrLd_jjrLjdd d}|	sjjr|sd_jjrjdd d}|rtdj  |rttjjdjjid d S jr|	r|
s|	}
|
|	   }n|
s|	}
|	s|
}	j dkr|
|	   }nj dkr8|dkr|
|	   }n`j dkrz|dkr\|
|	   }n|dksp|dkr|	  }
nj dkr|dkr|	  }
|
| dkrd}|
}d} dkr|
  }|
  }g }g }i }|D ]}|}|dkr||7 }d}j||||||| d\}}|| || | |_| |_ t!|d |_"t
  |#  W 5 Q R X qt$|_t%|_t!t&|' | j(td t)d!_t!|
_j dkr|d"kr|jjkrjdd |dkr|jjkrjdd n j dkr:|d#kr|jjkrjdd nΈj dkr|d"kr|jjkrjjdd |dkr|jjkrjdd |dkr|jjkrjdd nTj dkr|dkr|jjkrjdd |d#kr|jjkrjdd |r&ttjjdjjid td$j  d S )%Nc                      sJ   j r
dS  dkrdS js dS js0js0dS jrFjrFjsFdS dS )NTr   F)r~   r   r   r   r   r.   rx  rB   r.   r/   check_exit_conditionsC  s    z;CmfGanttTask._calc_resources.<locals>.check_exit_conditionsr7   z&_calc_resources start. gantt_task_id: r   rG   rl  rm  --rH      r  rn  r|   r9   r   T)r)  )r*  z4_calc_resources exit_conditions_met. gantt_task_id: ri  r  r=   r<   r   rE  rV  r:   i@8  )rq  rf   rp   rg   )rV  rE  )rV  r   z'_calc_resources finish. gantt_task_id: )*rA   r/  r0  rS   r   r   r#   rr  rY   rW   r&   r  rs  r   r{   r   rj   r   r   rt  r   r   r   r   rI  r  r   r{  ru  r   r  Z
date_startZdate_endrq   rV  r(   r   r   sumvaluesrk   r   )rB   r   rw  r  Z_tth_filterZ	havy_taskrv  r   r   r   rE  Zinitial_workZinitial_durationrV  Z	do_returnry  rz  Zstart_timesZ	end_timesr  ro  rp  r  r  r.   r  r/   r  A  s    











  







$




zCmfGanttTask._calc_resourcesc                 C   s,   |  |   | jp| j}|r(| | d S rC   )r   rU   r   r   r]  rB   r   r.   r.   r/   task_copy_hook  s    zCmfGanttTask.task_copy_hookc                 C   s<   |  |   |   | jd|d |   | jdd d S )NrV  )r   rw  Tr   )r   rU   r%   r  r   r(   )rB   rw  r.   r.   r/   task_resources_changed_hook  s
    z(CmfGanttTask.task_resources_changed_hookc                 C   s   |sd S |  |   |   |rN|  j|7  _|  j|7  _| jdd d S |  j|7  _|d krp| j| | _| jdd | jdd d S )NTr   r<  )r   rU   r%   r   r1  r(   r   r=  )rB   r5  r  Zfrom_tth_restorer.   r.   r/   timetracker_add_work_hook  s    	z&CmfGanttTask.timetracker_add_work_hookc                 C   s<   |  |   |   |  j|7  _|   | jdd d S NTr   )r   rU   r%   r>  r@  r(   r?  r.   r.   r/   timetracker_add_cost_hook  s
    z&CmfGanttTask.timetracker_add_cost_hookc                 C   sp   |  |  ddg  d}| jjr@| jjjjdkr@| jj| _d}| jr\| jj| _|   d}|rl| j	dd d S )Nrb   task.parentF
CmfProjectTr   )
r   rU   r   r   r{   
class_namer   r   check_gantt_projectr(   )rB   Z	need_saver.   r.   r/   task_parent_is_changed_hook  s    

z(CmfGanttTask.task_parent_is_changed_hookc                 C   s   |    d S rC   )r   rD   r.   r.   r/   rF  &  s    z2CmfGanttTask._do_timetracker_sched_work_is_changedc                 C   s(  |rL|j dkrL| jsL| |   |   | j  |   | jdd d S |r|j dkr|r|j dkr| |   |   | j  d| _	| 
  |   | jdd |   d S |r$|j dkr$|r$|j dkr$| |   |   d | _d| _	| 
  |   | jdd |   d S d S )NZIN_PROGRESSTr   r   rf   r   )r   r   r   rU   r%   Zset_nowrO  r(   r   r   rP  r;  r   )rB   Z
old_statusZ
new_statusr.   r.   r/   task_status_is_changed_hook)  sF    

z(CmfGanttTask.task_status_is_changed_hookc                 C   s   |  |   | js tddd |   | jszT| jj| _| jj| _	| jj
sT| j	j
r|   |   |   |   | jdd W nJ tk
r } z,td| jj d| jj dt| d W 5 d	}~X Y nX d	S )
u  
        Задача находится в списке с включенной опцией "Выставлять даты списка в плановые даты задач"
        Меняем плановые даты на даты из списков
        u?   У гант-задачи нет ссылки на задачу.Tr   r   u(   Плановые даты задачи "r   u   ) не изменились                            при попытке выставления дат от спринтов из-за ошибки: "r  N)r   rU   r   r   r%   r~   plan_start_dater   plan_end_dater   r   r  r   r!  r  r(   ZCmfAbortErrorr   r   r  )rB   r  r.   r.   r/   task_plan_dates_is_changed_hookP  s$    

z,CmfGanttTask.task_plan_dates_is_changed_hookc                 C   s&   |  |   |   | jdd d S r  )r   rU   r  r(   rD   r.   r.   r/   task_logic_type_is_changed_hookh  s    z,CmfGanttTask.task_logic_type_is_changed_hookc                 C   s,   |  |   | jj| _| jjr(|   d S rC   )r   rU   r   r   r   r(   rD   r.   r.   r/    task_parent_task_is_changed_hookm  s    
z-CmfGanttTask.task_parent_task_is_changed_hookc                 C   s0   |  |   | jj| _|   | jdd d S r  )r   rU   r   r   r  r(   rD   r.   r.   r/   "task_gantt_project_is_changed_hooks  s    
z/CmfGanttTask.task_gantt_project_is_changed_hookc                 C   s0   |  |   | jr,d | _d| _| jdd d S )Nr   Tr   )r   rU   r   r   r(   rD   r.   r.   r/   $task_has_child_tasks_is_changed_hooky  s
    z1CmfGanttTask.task_has_child_tasks_is_changed_hookc                 C   s4   |  |   | jd dd |   | jdd d S )NTrT  r   )r   rU   r  r   r(   rD   r.   r.   r/   *additional_children_relations_changed_hook  s    z7CmfGanttTask.additional_children_relations_changed_hookc                 C   s    | j jrd| _ |  j |7  _ d S r   )r   rh   )rB   r5  r.   r.   r/   r2    s    z CmfGanttTask.from_child_add_workc                 C   s    | j jrd| _ |  j |7  _ d S r   )r7  rh   r?  r.   r.   r/   r8    s    z CmfGanttTask.from_child_add_costc              	   C   s(  | j jrd| _ |  j |7  _ | jsD| j | _| jjp4d| jjp>d }n~| j | jks| j d  d| j d  d}| jd  d| jd  d}td| d| d| j dd	d
 | j jpd| j jpd }|  r$| jj	dkr$t
 < |  }||   || |  |jdd	d W 5 Q R X d S )Nr   rA  rB  rC  u;   Превысили План на Трудозатраты ( <= +   ) в родительской задаче ub   . Увеличьте в ней план или введите меньше Трудозатрат.Tr   rF   Fr  )rG  rh   r;   r   r   r   r   r   rE   rV   r&   r  r   rU   rH  r   r(   )rB   r5  rG  r   r   r.   r.   r/   rH    s(    

z%CmfGanttTask.from_child_agregate_workc              	   C   s   | j jrd| _ |  j |7  _ | js,| j | _n2| j | jks^td| j  d| j d| j ddd |  r| jjdkr| j jp|d| j j	pd }t
 2 |  }||   || |jdd	 W 5 Q R X d S )
Nr   u1   Превысили План на Расходы (r  r  u[   . Увеличьте в ней план или введите меньше РасходовTr   rF   r   )rJ  rh   rK  r   r   r   rE   rV   r   r   r&   r  r   rU   rL  r(   rM  r.   r.   r/   rL    s     


z%CmfGanttTask.from_child_agregate_costc                 C   s   |  | dS )u   
        Оповестить родителя, что ему нужно пересчитать свой агрегат actual_complete
        N)r   )rB   r   r.   r.   r/   !from_child_update_actual_complete  s    z.CmfGanttTask.from_child_update_actual_completec              	   C   sP   |   sdS t 2 |   }||   ||  |jdd W 5 Q R X dS )uP  
        Оповещение родителя.
        Передаем себя, т.к. мы еще можем быть не сохранены и родитель не сможет получить наши данные
        Другой вариант: опочещать через отдельный таск в celery
        NFr6  )rE   r&   r  r   rU   r  r(   )rB   r   r.   r.   r/   r     s    

z1CmfGanttTask.notify_parent_update_actual_completec                 C   s   | j s^| jr^dd | jddD }|ddddh }|r^| jj  | jjr^| jjjd	| jd
 | jjrx| jrxt	ddd | j
jr| jrt	ddd | jjs| jjr| jr| jr| j| jk rt	ddd | jjr| js| jdkrt	ddd d S )Nc                 S   s   h | ]\}}|qS r.   r.   )rP   k_r.   r.   r/   	<setcomp>  s     z0CmfGanttTask.check_user_input.<locals>.<setcomp>Tr   r   parent_task_idr   gantt_project_idzPPP-TSK-SCHEDULE)obju   Нельзя менять поле "Фактические трудозатраты" у Summary-задач. Используйте поле "Фактические трудозатраты по собственным ресурсам задачи"r   u   Нельзя менять поле "Фактические Затраты" у Summary-задач. Используйте поле "Фактические Затраты по собственным ресурсам задачи"u\   Нельзя выставить Дату начала позже Даты окончанияrQ  u   Этот вариант рассчета процента завершения можно использовать только у Summary-задач)rf  r   itemsr   r   r1   Zcheck_project_role_accessr   r~   r   r7  r   r   r   )rB   Zchanged_fieldsr.   r.   r/   check_user_input  s0    zCmfGanttTask.check_user_inputc                 C   s   | j jrd| _ | jjrd| _| jjr*d| _| jjr8d| _| jjrFd| _| jjrTd| _| jjrbd| _| jjrpd| _| j	jr~d| _	| j
jrd| _
| jjrd| _| jjrd| _| jjrd| _d S r   )r   rh   rJ  r   r7  r   r   rG  r   r1  r   Zconstrain_slackZconstrain_slack_pcttotal_slackrD   r.   r.   r/   r%     s4    zCmfGanttTask.fix_null_variablesr   c           
      C   st  t d| j d|  | jjdkr(d S | jjr| jr| jjrZ| j| jjkrZd}| jj}nH| jjs| jr| jj	| 
  | jjj| jdd | jjjdd d S t| jp| jp| jp| jp| j}|s|s| js| jjdks| js|s| jjrp| jrp| j| jjkrp|rd S |rB|| _| j| j_| jjdd n,| jjsn| j  | jj| _| jjdd |s| jr|  }|D ]F}|jr|j| jkr|j| jd|d d	 |  |jdd q|sD|  rD|  }	|		| 
  |	jjdkrD|	jr|	j| jkrD|	j| jd|d d
 |	  |	jdd | jsp| jjrd| | jj | | j d S )Nz!check_gantt_project: gantt_task: z	, level: rF   T)r   r   r   )z	task.epicztask.subprojectr  )r   rg  level)r   r   r  )r/  r0  rS   r   rV   r   r   r   r,   r   rU   r  r(   boolr   r   r   r   r   r   Z_calc_gantt_projectr~   r]   _calc_outline_numberrE   r^  r]  )
rB   rg  r   r   Zfrom_importr  Zplan_fields_are_usedr   r   r   r.   r.   r/   r  	  s    
	





z CmfGanttTask.check_gantt_projectc                 C   s  t d| jjj d| jjj d|  |dkr<tddd |sH| jj}dd	| jgd
dddddggg}dd tj	j
|ddd
gdD }d }tjjddt| gdd	d ggdddddgd}|D ]}||jjj \}}	d }
|jj}|dkr|jj}
|	rtj|||	}n|dkr:|jj}
| j|	 }tj|||}nX|dkrd|jj}
|	rtj|||	}n.|dkr|jj}
| j|	 }tj|||}nq|
r|sqtj|||
r|} qq|s| jr| jj}||  |js|j||d d}|S )Nz0_get_task_blocking_back_movement start task_id: r(  z
), depth: rf   uY   DEV: Защита от рекурсии: _get_task_blocking_back_movement: if depth > 100Tr   rL   rG   rJ   rT   system.finish:startsystem.finish:finishsystem.start:startsystem.start:finishc                 S   s$   i | ]}|j j|jj|jpd fqS r   )rM   rS   Zrelation_typer   r   rO   r.   r.   r/   
<dictcomp>g	  s    zACmfGanttTask._get_task_blocking_back_movement.<locals>.<dictcomp>rM   r   rH   r   r   z	task.nameztask.idr   r   project.calendar.timezoner  )target_datedepth)r/  r0  r   r   r{   r   r   r   r#   rX   rY   r   rW   keysrS   r   r|   r   r   r   r   r   r   r,   r   rU   r    _get_task_blocking_back_movement)rB   r  r  Z
_filter_inZbefore_tasks_with_lagsZblocking_gantt_taskZbefore_gantt_tasksZbefore_gantt_taskZrel_type_coder   Zbefore_dater|   r   r   r.   r.   r/   r  Z	  s`    (






z-CmfGanttTask._get_task_blocking_back_movementc                 C   s  | j js| jjrtd| jjj d| jjj d| d| j j	 d| j j
 
 | j j	ol| j j
ol| j j	| j j
k }| jj	o| jj
o| jj	| jj
k }|s|r|r|  }|rtd|jj ddd	 d
d| jgddddddggg}tjj|drttjjd| jjid d S )Nz-_check_start_finish_relations start task_id: r(  z), from_save: z sched_finish_date_new: z, self.sched_finish_date.old: uB   Перемещение заблокировано задачей "uz   " с исходящей связью ОН/ОО/НН/НО. Удалите связь и попробуйте еще раз.Tr   rM   rG   rJ   rT   r  r  r  r  r}   r   r  )r   r   r   r/  r0  r   r   r{   r   r   r   r  r   r#   rX   r   r  Zsort_task_by_order_relationsrS   )rB   	from_saveZfinish_date_is_chagnedZstart_date_is_chagnedZblocking_taskZ_filter_outr.   r.   r/   r   	  s    <  
z*CmfGanttTask._check_start_finish_relations)r  rg  from_sort_orderc                   s   |r|    | j|| | j|d | jjr:| jjdd |   |   |   | 	  t
 j||}| jjrtjj| j| j d | jjrtjj| j| j d |s| jdd |S )N)rg  Tr   )r   r   )r  )r  rc  rh  r   r   r(   r  r%   _alert_task_agile_plan_datesr  rc   r   r#   Z
CmfCommentZadd_comment_auditZ	html_diffr   r   )rB   r  rg  r  rb  r  rm   rd   r.   r/   r(   	  s$    zCmfGanttTask.savec                    s   |    t j|| d S rC   )r   rc   _save_importra  rd   r.   r/   r  	  s    zCmfGanttTask._save_import)TEXKOM_db_deletefrom_task_deletec                   s   |  ddddddg | jr(| | j |rnt| j tjj	| jddD ] }t| d |_
|jdd	 qJn"| jr| jj
| kr|std
dd | jr| jj
| kr| | jp| j t j|d|i|S )Ntask.op_gantt_taskztask.cmf_deletedr   r   outline_index_numr^   T)r,   include_deletedr   uY   Нельзя удалять Оперативную гант задачу у задачи!r   r  )r   r   outline_remover   r/  r0  rS   r#   r   rW   r,   r(   r   r   r^  rc   rs  )rB   r  r  rb  r  r   rd   r.   r/   rs  	  s$     
zCmfGanttTask.deletec                    sF   |  dddg t j||}| jrB| jj| krB| | jp>| j |S )Nr  r   r   )r   rc   restorer   r,   r]  r   r   )rB   rb  r  rm   rd   r.   r/   r  	  s
    zCmfGanttTask.restorec                    s@   t  jf | | jrd S td tj| dd td d S )N_CmfAutomationCrudTrigger startupdateZbefore_save_CmfAutomationCrudTrigger end)rc   before_save_hookrf  r/  r0  r#   CmfAutomationCrudTrigger	crud_hookrB   r  rd   r.   r/   r  	  s    
zCmfGanttTask.before_save_hookc                    s@   t  jf | | jrd S td tj| dd td d S )Nr  r  Z
after_saver  )rc   before_save_data_hookrf  r/  r0  r#   r  r  r  rd   r.   r/   r  
  s    
z"CmfGanttTask.before_save_data_hookr  c              	   C   sj   t jr| jsd S t jt jjjdg|| jj| jddt j| jjd}td|d  ||d |d gd d S )Nproject_notifyTr  )ZinitiatorSessionTabIdZinitiatorCurrentPersonactionZinitiatorActionZinitiatorObjIdZinitiatorObjChangedFieldsu   initiatorСomponentId	projectIdzproject_notify-r  )ZroomZevent_persons)	r/  Zsession_tab_idr>   Zcurrent_personrS   r{   r  Zcomponent_idZcmf_emit_event)rB   Zinitiator_actionZeventr.   r.   r/   r  
  s    
zCmfGanttTask.project_notifyc                 C   s(  | j js| jjsd S d}d}| jjr<| j r<| j | jjk r<d}| jjr\| jr\| j| jjkr\d}g }|sh|r| jddg | jjD ]:}|r|jr| j |jk s|r|jr| j|jkr|| q|r$d| jj	 d| jj
 dt|dkrd	nd
 d}|D ]}|d|j	 d|j
 d7 }qt|d d S )NFTzlists.plan_start_datezlists.plan_end_dateu   Задача "r   uI   ) выходит за диапазон плановых дат спискr  u   аu   oв: r(  z),,)r   r   r   r   r  r  r   Zlistsr   r   r   r   r   rstrip)rB   Zalert_start_dateZalert_end_dateZalert_listsZ	task_listr  Zlstr.   r.   r/   r  *
  s@    

0z)CmfGanttTask._alert_task_agile_plan_datesc                 C   s  | j jdkrd S ddddd}d }| D ]}t| |}|jr*|jrd }d }|dkrd}|jr|jd	 |jd	  }}|d
d|d
d}|jd	 |jd	  }	}
|	d
d|
d
d}|dkrt|s|  }|j}|r|t	 }|t
j|jjd }|jt	 }|t
j|jjd }t|jjd	 d	\}}d|dd|d
}|d d| }|rp|d d| nd}td| j j d| j j d||  d|p|j d|p|j d q*|js*|jr*td| j j d| j j d||  d q*d S )NrF   u)   Плановая длительностьu)   Плановые трудозатратыu&   Плановая дата началаu,   Плановая дата окончания)r   r   r   r   )r   r   u   НетrA  Z02drB  u   мин)r   r   rt   zUTC z+03dr  z%Y.%m.%d, %H:%Mr  u   DEV: У задачи r(  u   ) изменено поле "z":                        c u    на r   u.   ) сброшено значение поля "z".)r   rV   r  r   r   r   r   ru   Z
astimezoner   rv   rx   rw   r{   divmodstrftimer   r   r   )rB   r   r|   rd  r-   Znew_value_strZold_value_strZold_hourZ
old_minuteZnew_hourZ
new_minuteZdate_oldZdate_newr~  r  Ztime_suffixr.   r.   r/   r   K
  sR    

"

z'CmfGanttTask._alert_changed_plan_fieldsc                 C   s   | j js| jjsd S | jjdkr6d| _d| _d | _d S | j jrr| j sr| j jrn| j}| jjrb| jj}| j	|d d S | j sd| _d| _d | _d S | j jr| j r| j js| 
  d S | jjr| js| j	| jjd | 
  d S )NrF   r   )remove_from)r   r   r   r   rV   outline_numberoutline_parent_strr  r   r  outline_insert_downrf  r  r.   r.   r/   r  
  s:    z!CmfGanttTask._calc_outline_numberc              
   C   s   |  | jj| jj d| _| jr,| jjj| _t B t	j
jdgg dd| jgdd| jgddd gdd| jggd	j}W 5 Q R X |r|d
 | _nd
| _| jr| jr| jpd d| jjd| _n| jjd| _| jjrtt	j
j| jjjg| jjg| jjjgd d S )Nr   max__outline_index_numr   r   r   r   rS   r   )r   order_byrI   r  r   06rb  )_outline_lock_lvlr   rS   r   r  r,   r  r&   r  r#   r   r$   r  r  r{   r   r~   r  _outline_recalc_childrens)rB   Z	max_indexr.   r.   r/   r  
  s.    




z CmfGanttTask.outline_insert_downc              
   C   s  |  dddddg | | jj| jj d }|r\tjj|ddgd}|j| jkr\tdd	d
 | j	j
}|sd}d| _	d	}d}|}d}nH|jj	j
}||k rd	}|d | _	|d }|}d}nd}|| _	|}|}d}| jr| jpd d| j	j
d| _n| j	j
d| _d}	tjjj |	| jjj
| jjj
| jj
|||d}
dd |
D }dd |
D }| jjrl|| jjj
 |rttjj||| jjj
gd d S )Nr   r   r  r  r`   zop_gantt_task.outline_index_numr  u   outline_insert_after можно вызывать только для задач на том же уровне. Сначала измените parent_taskTr   r  Fr   r   r  a  UPDATE cmf_gantt_task SET
            outline_index_num = outline_index_num + :i,
            outline_number = (CASE WHEN outline_parent_str = '' or outline_parent_str is null THEN to_char(outline_index_num + :i, 'FM000000') ELSE concat(outline_parent_str, '.', to_char(outline_index_num + :i, 'FM000000')) END)
        WHERE
            (parent_task_id = :parent_task_id or (:parent_task_id is null and parent_task_id is null))
            AND gantt_project_id = :gantt_project_id
            AND outline_index_num >= :from_outline_index_num
            AND outline_index_num <= :to_outline_index_num
            AND parent_id is null
            AND id != :id
        RETURNING task_id, id
        )r  r  rS   from_outline_index_numto_outline_index_numic                 S   s   g | ]}|d  qS r   r.   rP   rr.   r.   r/   rR     s     z5CmfGanttTask.outline_insert_after.<locals>.<listcomp>c                 S   s   g | ]}|d  qS r  r.   r  r.   r.   r/   rR   	  s     r  )r   r  r   rS   r   r#   r   r$   r   r  r{   r,   r  r  	CmfPersondp_ddSessionexecuter   r~   r   r  r   r  )rB   Zprev_task_idZ	prev_taskold_outline_index_numZprev_outline_index_numZ	insert_upr  r  r  sqlrm   	child_idschild_gantt_idsr.   r.   r/   r   
  sZ    


z!CmfGanttTask.outline_insert_afterc                 C   s   | j s
d S d }|r|jj}| | jj| d| _d| _t| j }d | _ d}tj	j
j ||| jjj|| jjd}dd |D }dd |D }|rttjj||| jjjgd | jr| jjrtjj| jjjdgd	j| jj_d S )
Nr   a}  UPDATE cmf_gantt_task SET
            outline_index_num = outline_index_num - 1,
            outline_number = (CASE WHEN outline_parent_str = '' or outline_parent_str is null THEN to_char(outline_index_num - 1, 'FM000000') ELSE concat(outline_parent_str, '.', to_char(outline_index_num - 1, 'FM000000')) END)
        WHERE
            (parent_task_id = :parent_task_id or (:parent_task_id is null and parent_task_id is null))
            AND gantt_project_id = :gantt_project_id
            AND outline_index_num >= :old_outline_index_num
            AND parent_id is null
            AND id != :id
        RETURNING task_id, id
        )r  r  r  rS   c                 S   s   g | ]}|d  qS r  r.   r  r.   r.   r/   rR   ,  s     z/CmfGanttTask.outline_remove.<locals>.<listcomp>c                 S   s   g | ]}|d  qS r  r.   r  r.   r.   r/   rR   -  s     r  r  r  )r  rS   r{   r  r   r  r  rq   r#   r  r  r  r  r  r  r   r  r   r,   r   )rB   r  Zremove_from_idr  r  rm   r  r  r.   r.   r/   r    s0    
zCmfGanttTask.outline_removec                 C   s   t d| d|  d S )NZOUTLINE_NUMBER_r  )r&   Zcache_obj_lock_get)r)   r  r  r.   r.   r/   r  5  s    zCmfGanttTask._outline_lock_lvluY   Вычисление структурных номеров у дочерних задач)rj  r  c                    s   t d tjjtjj|  tjjtj	j| g g   fddt d |  t d tjjtjj tjjtj	j  t d d S )Nz)_outline_recalc_childrens init invalidatec                    s   t dt|   | D ]}tj| qt d d}tjjj	 
|t| d}g }|D ]6}|d r|||d  |d   |d  qb|r| d S )Nz3_outline_recalc_childrens recalc_subtree start len=z2_outline_recalc_childrens recalc_subtree locks seta  UPDATE cmf_gantt_task SET
                outline_parent_str = pg.outline_number,
                outline_number = (CASE WHEN pg.outline_number = '' or pg.outline_number is null THEN to_char(ugt.outline_index_num, 'FM000000') ELSE concat(pg.outline_number, '.', to_char(ugt.outline_index_num, 'FM000000')) END )
            FROM
                cmf_gantt_task ugt
                LEFT JOIN cmf_task pt ON pt.id = ugt.parent_task_id
                LEFT JOIN cmf_gantt_task pg ON pt.op_gantt_task_id = pg.id
            WHERE
                ugt.parent_task_id IN :parent_task_id_list
                AND ugt.gantt_project_id = :gantt_project_id
                AND ugt.id = cmf_gantt_task.id
                AND ugt.parent_id is null
            RETURNING ugt.task_id, ugt.id, (select cmf_task.has_child_tasks from cmf_task where cmf_task.op_gantt_task_id = ugt.id) as has_child_tasks
            )Zparent_task_id_listr  r~   r   rS   )r/  r0  r   r#   r   r  r  r  r  r  r  tupler   )Zparent_id_list	parent_idr  rm   Zrecursive_parent_id_listtZfinish_gantt_invalidateZfinish_invalidater  recalc_subtreer.   r/   r  F  s"    
z>CmfGanttTask._outline_recalc_childrens.<locals>.recalc_subtreez._outline_recalc_childrens start recalc_subtreez+_outline_recalc_childrens finish invalidatez_outline_recalc_childrens end)
r/  r0  cmfapp	CMF_CACHEinvalidate_idsr#   r   r  r   )ZidsZgantt_task_idsr  r.   r  r/   r  ;  s    
"

z&CmfGanttTask._outline_recalc_childrensuB   Перевычисление структурных номеровc                 C   s$  | r| g}n*t jjddgdddgdd}dd	 |D }td
t|  |D ]} td|  d t }|d  |rN| }td|  d|  d}t j	j
j ||| d}t }|D ](}|d r||d  ||d  qt  td tjjt jjt| td qtqNd S )Nr  rS   rV   r   rF   T)r   rI   Zinclude_systemc                 S   s   g | ]
}|j qS r.   r  r  r.   r.   r/   rR   w  s     z6CmfGanttTask._outline_force_recalc.<locals>.<listcomp>u<   _outline_force_recalc Всего гант-проектов: u/   _outline_force_recalc обрабатываем u   . Уровень 0u   . Дочки от u
  WITH gt AS (
                    select g.id, g.task_id, g.parent_task_id, x.num
                    from
                        cmf_gantt_task as g
                        inner join cmf_task t ON t.id=g.task_id
                        inner join unnest(array(
                            SELECT cmf_gantt_task.id from cmf_gantt_task inner join cmf_task ON cmf_task.id=cmf_gantt_task.task_id
                            WHERE
                                -- Основной WHERE. Нужен чтобы верно рассчитались номера
                                cmf_gantt_task.parent_task_id = :parent_task_id OR (:parent_task_id is null and cmf_gantt_task.parent_task_id is null)
                                AND cmf_gantt_task.gantt_project_id = :gantt_project_id
                                AND cmf_gantt_task.cmf_deleted = false
                                AND cmf_gantt_task.parent_id is null
                            ORDER BY
                                cmf_gantt_task.outline_number, cmf_task.orderno, cmf_gantt_task.cmf_created_at
                        )) WITH ORDINALITY AS x(id, num) ON x.id=g.id
                        WHERE
                            -- Дубль WHERE. Нужно чтобы PG не селектил все гант-таски в cmf_gantt_task as g
                            g.parent_task_id = :parent_task_id OR (:parent_task_id is null and g.parent_task_id is null)
                            AND g.gantt_project_id = :gantt_project_id
                            AND g.cmf_deleted = false
                            AND g.parent_id is null
                        ORDER BY
                            -- Дубль сортировки
                            g.outline_number, t.orderno, g.cmf_created_at
                )
                UPDATE cmf_gantt_task SET
                    outline_index_num = gt.num,
                    outline_parent_str = pg.outline_number,
                    outline_number = (CASE WHEN pg.outline_number = '' or pg.outline_number is null THEN to_char(gt.num, 'FM000000') ELSE concat(pg.outline_number, '.', to_char(gt.num, 'FM000000')) END )
                FROM
                    gt
                    LEFT JOIN cmf_task pt ON pt.id = gt.parent_task_id
                    LEFT JOIN cmf_gantt_task pg ON pt.op_gantt_task_id = pg.id
                WHERE
                    gt.id = cmf_gantt_task.id
                RETURNING gt.task_id, (select cmf_task.has_child_tasks from cmf_task where cmf_task.id = gt.task_id) as has_child_tasks
                )r  r  r~   r   z&_outline_force_recalc cache invalidatez-_outline_force_recalc finish cache invalidate)r#   r   rY   r/  r0  r   r  r  popr  r  data_driverr  r  
cmf_commitr  r  r  r  r  rW   )r  Zgantt_project_id_listrm   Zprocess_parent_id_setr  r  Zclean_cache_idsr  r.   r.   r/   _outline_force_recalcp  s4    
&
z"CmfGanttTask._outline_force_recalcc                 C   s   t tjjd| id d S )Nr>   r  )r  r#   r   calc_critical_path_job)r>   r.   r.   r/   r     s    zCmfGanttTask.calc_critical_pathr>   u.   Расчет критического пути)r	  r
  r  rk  rj  c              
      sL  fdd
fddfddd% 	f	dd		t jj| d
gd}|sntd|  ddd |jj}||  |jddd t j	
 \}i t tdddddg t 
|jj
|jj< t t 	dddddddddg	dd|jgddd gd!dd gg}d"d# t jj|d$D t D ]}| q8d S )&Nc                    s.   | kr&t jjdd| g d}|| < |  S )NrS   rG   rH   )r#   r   r$   )ri  r+   )r   gantt_tasks_by_idr.   r/   _get_gantt_task  s    z<CmfGanttTask.calc_critical_path_job.<locals>._get_gantt_taskc                    sn   | j  krddd| j gdddgddd gg}dg}tjj||d}|sVtd| j  d	d
 |jj | j <  | j  S )Nr>   rG   r_   rF   r   r   rH   uW   Не найдена гант-задача у гант-проекта в проекте Tr   )r>   r#   r   r$   r   r   r{   )r+   r   _fieldsZgantt_project_gt)project_end_datesr.   r/   _get_project_finish_date  s    

zECmfGanttTask.calc_critical_path_job.<locals>._get_project_finish_datec                    sB   | j  kr8| ddg | jjp0tjjddgd | j <  | j  S )Nzproject.calendarr  r   rw   r   )r>   r   r   r|   r#   r   r$   )r+   )calendars_by_project_idr.   r/   ru     s    
 z:CmfGanttTask.calc_critical_path_job.<locals>._get_calendarFc                    sl  | }|j jkrd S |r*||j j< n*|j jd }|sT|jrT|jjd }d |_d |_d |j_d|_|j	r|j
r|js|jjs|jjs|jjs|jjr|jdd d S |sd}td| d|j  |jr|s|jjkr|jj|d d d S |j jkr$tddd	 n|j j |}|j jkr@g }|rX|| |j j D ]^\}}||d d |krd| j}	|rtjj||	t| d
}	||	 qd|r@t|}|jjs@||_tjj||jjt|j d
|_tjj||j
j|jjd|_|jjdk|_|jdd |rR||j j< |jjr|jdg dd |jjD }
d }d }d }d}|
D ]}||d|d d |d }|sq|r|jrt||jn|j}|r|jrt||jn|j}|r|jrt||jn|j}|s|jrd}q||_|jr|pR||_tjj||j
j|jjd|_|jjdk|_n||_||_||_|jdd |jjd ks|jjd kr@|rt|||_n
||_tjj||jjt|j d
|_tjj||j
j|jjd|_|jjdk|_|jdd  |jj|jj|jj|jjd|j j< d S )NFTr   r  zcalc_critical_path: level: z, )r  u@   calc_critical_path: Обнаружен цикл в связях.r   )r|   r   r   )r|   r   r   r   zchild_tasks.op_gantt_taskc                 S   s   g | ]}|j jqS r.   )rN   r{   )rP   r  r.   r.   r/   rR   B  s     zRCmfGanttTask.calc_critical_path_job.<locals>._calc_is_critical.<locals>.<listcomp>)late_start_datefrom_parent_taskr  )r
  late_finish_dater  is_critical_path)rS   r{   r$   r   rN   r
  r  r  r  r   r   r   r   r(   r/  r0  r   r   r  r   r#   r   r   rq   r   r~   r   r   r   r   r   )ri  r
  r  r  r+   Z#following_tasks_min_late_start_dateZfollowing_late_start_datesZfollowing_gantt_task_idr   Zfollowing_late_start_dateZchildren_gantt_task_idsZmin_child_late_start_dateZmax_child_late_finish_dateZmin_child_total_slackZhas_critical_path_childZchild_gantt_task_idZdone_child_task)	CriticalPathValues_calc_is_criticalru   r  r  done_gantt_tasksgiven_late_start_date_by_gt_idtask_out_linksvisited_gantt_tasksr.   r/   r    s   









z>CmfGanttTask.calc_critical_path_job.<locals>._calc_is_critical main_gantt_project.op_gantt_taskr  u   Проект с id "u   " не найден.Tr   )r  r  r  r
  r  r  r  r   r   r   r   r`   r^   r   rG   r_   r   rF   r   c                 S   s   i | ]}|j j|qS r.   )rS   r{   )rP   r+   r.   r.   r/   r    s      z7CmfGanttTask.calc_critical_path_job.<locals>.<dictcomp>rH   )NFN)r#   r  r$   r   main_gantt_projectr,   r   rU   r  rX   Zget_start_finish_graphsr  r   dictr   r{   r>   r   rW   r  )r>   r   Zgantt_project_gantt_taskr  r   ri  r.   )r  r  ru   r  r  r	  r  r   r  r  r  r  r  r/   r    s@      
   
z#CmfGanttTask.calc_critical_path_jobu*   Пересчет гант проектовc           	      C   s  g }| rdd| g}t jjdg|dD ]v}|j}|s6q$d|j_d|j_d|j_d|j_dd|gdd|gddd gd	d
dd gd
ddggddd gdddggddd gdddggddd gdddgggg}d
dddg}d}t j	j||d g||dgd}|sqp|D ]l}|j j|jj
pd7  _|j j|jj
p*d7  _|j j|jj
pDd7  _|j j|jj
p^d7  _q|d7 }q|jj|j_|jj|j_|jjdd t  q$d S )Nr   rG   r  )r   rI   r   r  rF   ra   r  r   r   r   r7  r     Zcmf_created_at)slicerI   r   r  Tr   )r#   r  rW   r  r,   r   rG  r7  rJ  r   r{   r   r   r(   r  )	Zproject_codeZproject_filterr   r   rI   r   r  r   r+   r.   r.   r/   recalc_gantt_projects  sh    

z"CmfGanttTask.recalc_gantt_projectsc                    s    fdd}t tdddg| gdddd	g | }d
ddg}dg}tdd tjj|d|dD }dd|g| }|| |rdd|g| }qS )Nc                     s   t  } d}d}tjj ||| gdd}|s0q|D ]V}|jsZ|jrZ|jj |j q4|jr4|j	j
s4| |j	j |j	j |j q4||7 }q| S )Nr  r   T)rI   r   r  include_archived)r  r#   r   rY   r  r  r   rN   r  r   cmf_deleted)Z
parent_idslimitstepZtasksr   r  r   treer.   r/   update_tree  s&    

z0CmfGanttTask.get_gantt_tree.<locals>.update_treer~   rG   Fzparent_task.op_gantt_task_idzgantt_project.op_gantt_task_idrN   zparent_task.cmf_deletedrl  factr  c                 S   s$   h | ]}|j r|j d r|j qS )r   )r  
startswith)rP   rv  r.   r.   r/   r    s     z.CmfGanttTask.get_gantt_tree.<locals>.<setcomp>T)rI   r  r   rS   rT   )r   r  rW   r#   rr  rY   r  )leaf_filterr   Zparent_ids_setZ
tth_filterZ
tth_fieldsZtask_ids_from_tth_factZparent_ids_set_from_tthr.   r  r/   get_gantt_tree  s"    



zCmfGanttTask.get_gantt_treec               
      sZ   fdd dddddgdddggdddgdddggd	ddgd	ddggd
ddgd
ddgggddddgdddggdddgdddggdddgdddggdddgdddgggg} t d tjj| dtdd tjj}tjj}tjjj	
 }t }dd  D }|| }t||B }||jt|j||j|jkt|j||jdk|jdk|j }dd |D }	d}
tdt||
D ]}||||
  }ddddddd g}tjj d!d"|g|d#d$}|D ]}|j|j d%< |j!pd|j d< |j"pt#d&|j d< |	$|jd|j d < |j%pBt#d&|j d< |j&pXd|j d< |j'prt#d&|j d< qؐqd}|D ]L} | |d'7 }|d( dks|t|krt d)| d*t| d+ qrN|(|j)* +|jt,d%kjt,dt,dt,dt,dt,d,t,d-d.t  t-  t./  t d/ nt d0 dS )1u   
        Пересчитывает 'actual_work', 'actual_cost', 'sched_work', 'sched_cost' от детей к родителям
        c                    s^  | |  d< | kr0|  d |  d< |  S d|  d< d|  d< d|  d< d|  d< |  }|D ]l} |}|  d  |d 7  < |  d  |d	 7  < |  d  |d 7  < |  d  |d 7  < ql|  d  |  d 7  < |  d  |  d
 7  < t |  d |  d |  d< t |  d |  d	 |  d	< |  S )Nri  r1  r   r   rJ  rG  r7  r   r   r>  )r   )Znode_idchildrenZchild_idZ
child_datacalculate_nodeZ	node_datar  r.   r/   r'  '  s(    ""z6CmfGanttTask.recalc_gantt_tree.<locals>.calculate_noder  zop_gantt_task.actual_workr   Nr   zop_gantt_task.sched_workzop_gantt_task.actual_costzop_gantt_task.sched_costz%parent_task.op_gantt_task.actual_workz$parent_task.op_gantt_task.sched_workz%parent_task.op_gantt_task.actual_costz$parent_task.op_gantt_task.sched_costu(   Получаем дерево задач)r#  c                   S   s   dddddddS )Nr   )r   r   r7  r   rJ  rG  r.   r.   r.   r.   r/   <lambda>q      z0CmfGanttTask.recalc_gantt_tree.<locals>.<lambda>c                 S   s   h | ]}|D ]}|qqS r.   r.   )rP   r%  childr.   r.   r/   r  x  s       z1CmfGanttTask.recalc_gantt_tree.<locals>.<setcomp>r!  Fc                 S   s   i | ]\}}||pd qS r  r.   )rP   tidsr.   r.   r/   r    s      z2CmfGanttTask.recalc_gantt_tree.<locals>.<dictcomp>r  r  r   r7  r   r   r>  r1  rS   rT   T)rI   r   r  ri  0r  
   u   Обработано u    из u    ветокrG  rJ  )r   r7  r   r   rG  rJ  u:   Обновленные данные внесены в БДu/   Нет данных для обновления)0printr#   r   r$  r   Zdp_modelrr  r   r  r   r  r  r  r  rW   queryrS   r	   r  r  joinr   r  rI   r
   Zin_rl  r  Zgroup_byallranger   rY   r   r7  rj   r$   r>  r   r   r  Z	__table__r  wherer   r  r  Zflushdb)r#  Z	GanttTaskZTimeTrackerHistoryZsessionZparent_nodesZchild_nodesZ
root_nodesZ	all_nodesZtth_rowsZtth_sumZ
batch_sizer  Z	batch_idsr   r   r+   Zprogress_countrootr.   r&  r/   recalc_gantt_tree!  s    "& 
 


"



zCmfGanttTask.recalc_gantt_tree)N)NF)NF)FFF)F)F)F)N)NFNF)F)FFFFF)FF)F)FFFF)N)N)F)N)NF)NN)NF)N)FFNFr   )Nr   )F)r  )N)N)N)N)N)y__name__
__module____qualname__Z	api_allowr   Zapi_methodsclassmethodr0   r5   r3   r4   rE   r]   rU   propertyrn   rr   rs   ri   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ru   r   r   r  r  r  staticmethodZcmf_deferred_jobr  r  r!  r$  r&  r'  r   r+  r3  r:  r;  r=  r@  rI  rN  rO  rP  rR  rS  rU  rW  rZ  r[  r]  r^  r_  rc  re  rh  r{  ru  r  r  r  r  r  r  rF  r  r  r  r  r  r  r  r2  r8  rH  rL  r  r   r  r%   r  r  r   r(   r  rs  r  r  r  r  r  r   r  r  r   r  r  r  r  r   r  r  r$  r6  __classcell__r.   r.   rd   r/   r      s0  
!





&
'+_

!	


+
D_7

 
G     
D
#


   
=b  5= ''N?'


!<"G&
3
N

  \
I3r   )ry   rv   Zdateutil.tzr   decimalr   r   r   collectionsr   r   Z
sqlalchemyr   r	   r
   r   Z
cmf.fieldsZcmf.includeZ#modules.gantt.fields.cmf_gantt_taskr   r.   r.   r.   r/   <module>   s   