B
    afB                @   s\   d dl Zd dlmZ d dl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)*)CmfGanttTaskc                   s  e Zd ZdZedd ZedddZdd Zd	d
 Zg 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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dd*d+Zd,d- Zd.d/ Zdd0d1Zd2d3 Zd4d5 Zd6d7 Zd8d9 Z d:d; Z!d<d= Z"e#e$dd>gd?d@dA Z%ddBdCZ&ddDdEZ'dFdG Z(dHdI Z)dJdK Z*ddLdMZ+dNdO Z,ddPdQZ-dRdS Z.dTdU Z/ddVdWZ0dXdY Z1ddZd[Z2d\d] Z3d^d_ Z4d`da Z5dbdc Z6ddde Z7dfdg Z8dhdi Z9ddjdkZ:ddldmZ;dndo Z<dpdq Z=drds Z>ddtduZ?ddvdwZ@dxdy ZAddzd{ZBd|d} ZCd~d ZDdd ZEdd ZFdd ZGdd ZHdd ZIdd ZJdddZKdd ZLdd ZMdd ZNdddZOdddd fdd
ZPdd fdd
ZQ fddZR fddZSdddZTdd ZU  ZVS )r   Tc             C   s   t  }ddddddddd	d
dddg}t jjd ||d}|rVx|D ]}|| ||< qBW ||_|  t  |jdddd W d 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)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   sf   t  }|r| ||S |j  |j|_||_|  |j|_t	  |j
ddd W d Q R X |S )NF)r   r   )r   r   r&   r   loadr   _calc_projectr   r   r   r   )r   r   r    r!   r$   r$   r%   create_gantt_task"   s    

zCmfGanttTask.create_gantt_taskc             C   s   | j r| j jr| j j| _d S )N)r   r   )selfr$   r$   r%   r(   8   s    zCmfGanttTask._calc_projectc             C   s    | j r| j jS | jr| jjS d S )N)r   r"   r   )r*   r$   r$   r%   _get_parent_gantt_task=   s    z#CmfGanttTask._get_parent_gantt_taskc             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}|S )Nztask.gantt_projectr   z==r   r   )filterr   )save_preload_fieldsr   logic_prefixr   r   listr   )r*   
add_filterr   Zchild_gantt_tasksr$   r$   r%   _get_children_gantt_tasksC   s    


z&CmfGanttTask._get_children_gantt_tasksc                s0   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_projectzparent_task.op_gantt_taskztask.logic_prefixztask.parent_task.logic_prefixztask.has_child_tasksztask.plan_start_dateztask.plan_end_dateztask.responsibleztask.executors)superr-   )r*   r   )	__class__r$   r%   r-   [   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)rounding)r
   is_null_perform_completeDecimalquantizer   )r*   resr$   r$   r%   _perform_costq   s    zCmfGanttTask._perform_costc             C   s:   | j jrd S | j | j d }t|jtdtd}t|S )Nr4   1)r5   )r	   r6   r7   r8   r9   r   int)r*   r:   r$   r$   r%   _perform_durationx   s
    zCmfGanttTask._perform_durationc             C   s:   | j jrd S | j | j d }t|jtdtd}t|S )Nr4   r<   )r5   )r   r6   r7   r8   r9   r   r=   )r*   r:   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   )secondsr4   r<   )r5   )r   r6   r   _get_calendardttimezone	timedeltar=   datetimenowZget_work_timedeltavaluer8   r9   r   )r*   calendarZtzrF   Zdelta_finish_time_secZdelta_now_time_secZperform_completer:   r$   r$   r%   r7      s"    
zCmfGanttTask._perform_completeFc             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 )NFz0-constTu   невозможно изменить дату начала, если зафиксированы дата окончания и длительность u(   Фиксированное начало z%d.%m.%Yz3-afteru   Начало не раньше z4-beforeu   Начало не позже u   ограничение "uE   " конфликтует с плановой датой начала u<   Конфликт планирования: В задаче "z" (z) .)abort)	r   const_durationr   rG   r   r   namecode	cmf_alert)r*   estimated_datereturn_correct_datealertcorrect_datetext
constraint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 )NFz0-constTu   невозможно изменить дату окончания, если зафиксированы дата начала и длительностьrI   u.   Фиксированное окончание z%d.%m.%Yz1-afteru%   Окончание не раньше z2-beforeu#   Окончание не позже u   ограничение "uK   " конфликтует с плановой датой окончания u<   Конфликт планирования: В задаче "z" (z) rJ   )rK   )	r   rL   r   rG   r   r   rM   rN   rO   )r*   rP   rQ   rR   rS   rT   rU   rV   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)
        )NNNztask.gantt_project)z0-constz3-after)z0-constz2-beforeN)r+   r   r.   load_fieldsr-   get_parent_plan_limitr   r   maxr   r   minrL   r	   )r*   Zparent_start_limitZparent_finish_limitZparent_duration_limitparent_gantt_taskstart_limitfinish_limitduration_limitr$   r$   r%   rZ      s,    


z"CmfGanttTask.get_parent_plan_limitc       
      C   sF  d } }}| j jsdS x |  D ]}|jdkrV|sB|jj}n|jrVt||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|s`|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 jr$| \}}}	|s|}n|rt||}|s|}n|rt||}|s*|	}q$|	r$t||	}q$W |||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)
        N)NNN)z0-constz4-before)z0-constz2-before)z0-constz1-after)z0-constz3-after)r   has_child_tasksr1   r   r   rG   r\   r   r   r	   r   CmfCalendarget_date_by_durationrA   r=   r[   rL   get_childrens_plan_limit)
r*   r^   r_   r`   r!   r   r   Zch_start_limitZch_finish_limitZch_duration_limitr$   r$   r%   rd     s    







z%CmfGanttTask.get_childrens_plan_limitc             C   sB   t | ddrd S d| _|  \| _| _| _|  \| _| _| _	d S )N_calc_plan_limits_cache_doneFT)
getattrre   rZ   _plan_start_limit_min_plan_finish_limit_maxZ_plan_duration_limit_maxrd   _plan_start_limit_max_plan_finish_limit_minZ_plan_duration_limit_min)r*   r$   r$   r%   _calc_plan_limits_cache}  s
    z$CmfGanttTask._calc_plan_limits_cachec             C   s   | j rP| jrPtjj| jdpd}tjj|  | j j	| jj	| j
j	d}|| | _n| j jrf| jjrfd| _| jjr~| jd||d d S )N)r      )rH   Zfrom_dtZto_dtforce_include_endsr   T)from_calc_sched_durationfrom_child_changesfrom_sched_dates_changed)r   r   r   CmfTaskResAssigncountr   rb   get_duration_minutesrA   rG   rL   r	   old
is_changed_do_sched_duration_is_changed)r*   ro   rp   Znumber_of_recourcesZ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   )	actual_start_dateactual_finish_dater   rb   rs   rA   rG   actual_durationrt   )r*   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:
                плановая дата начала
        )rP   rQ   z1-after)r   rb   rc   rA   r   rG   r=   r	   rW   r   rg   )r*   rollbackrP   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:
                плановая дата окончания
        )rP   rQ   )	r   rb   rc   rA   r   rG   r=   r	   rX   )r*   r|   rP   r   r$   r$   r%   _calc_sched_finish_date  s
    z$CmfGanttTask._calc_sched_finish_datec             C   s   | j js| j dkrd | _d S | jjr0| jjr0d S | jrZ| jsZ| j|d| _|rVd | _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|   z1-afterz0-constu   Плановый период может не соответствовать плановой длительности, т.к. все переменные зафиксированы)
r	   r6   r   r   r~   r}   r   r   rL   rO   )r*   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 )Nr   )
rz   r6   ry   rx   r   rb   rc   rA   rG   r=   )r*   r$   r$   r%   _calc_actual_period  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   
        Вычисляет фактический % завершения
        z0-workr   r4   z5-timetrackerN)actual_complete_typeactual_workis_not_nullr   mathfloorr\   actual_completer6   $notify_parent_update_actual_completetimetracker_sched_work)r*   tmp_completer$   r$   r%   _calc_actual_complete  s    




z"CmfGanttTask._calc_actual_completec       
      C   s  | j jsdS | jdkrdS | jdkr(dS | jdkr| jdgd}|sHdS t|}d}x>|D ]6}|r|j|jkr||jjpzd7 }qZ||jjpd7 }qZW || }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}	x|D ]}|rx|j|j jkrx|j ddg ||j jjpNd7 }|j jjdkr|	|j jjprd7 }	n2||jjpd7 }|jjdkr|	|jjpd7 }	qW |	| d }n | jdkrdS | jdkrdS | j|k r|| _dS )uB   
        updated_ch_gantt_task - указан, когда
        Nz0-workz5-timetrackerz
1-completer   )r   r   z2-story_pointsztask.gantt_projectr   z==r   agile_story_pointszstatus.status_type)r,   r   =CLOSEDr4   z3-costz4-fixed)r   ra   r   r1   lenidr   rG   r.   r   CmfTaskr/   rY   r   statusstatus_type)
r*   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_complete.  sZ    




z+CmfGanttTask._calc_summarry_actual_completec             C   sb  |    | jdkr(| js.| jr.| j| _nd | _| jdkrB| j| _n| jdkr| j}| jrl| jrlt| 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r|  }|r|j	 }|r|| _n| jr.| j| _n | jr| j| _| jr.| j| _| jrX| jrX| j| jkrXt
ddd | jr| jr| j| jk rt
d	dd | jjr,| jr| jj| jk r,| jr| jj| jkr,| js| jj| _n\| jdkrnN| jd
kr| jj| jk r,| jj| _n&| jdkr,| jj| jkr,| jj| _| jdk| _| jrR| jjrR|   | jdd d S )N)z0-constz3-afterz4-beforez0-constz3-afterz4-beforez1-earlyu~   Нельзя указать Дату начала больше зафиксированной у дочерней задачиT)rK   u   Нельзя указать Дату начала меньше зафиксированной у родительской задачи)z1-earlyz4-before)z2-latterz3-after)r   )rk   r   r   r   rg   r[   ri   r\   r+   r'   rO   r   Zplan_start_datelock_sched_start_dateru   _do_sched_start_date_is_changedr   )r*   r   r]   parent_sched_start_dater$   r$   r%   #_do_constrain_start_date_is_changedr  sh    









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 )Nztask.gantt_projectout_linkr   zrelation_type.codezsystem.additional_parentin_link)r,   r   c             S   s   g | ]}|j jjqS r$   )r   rG   r   ).0Zrelr$   r$   r%   
<listcomp>  s    z8CmfGanttTask._get_parent_gantt_tasks.<locals>.<listcomp>r   task_idIN)r   r.   r+   rY   r-   appendr   CmfRelationOptionr/   r   r   extend)r*   parent_gantt_tasksr]   _filterZ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   s6   d }|  ddg | jr | jj}|p4tjjddgdS )Nzproject.calendarzproject.calendar.timezonezsystem:defaultrC   )rN   r   )rY   r   rH   r   rb   r   )r*   rH   r$   r$   r%   rA     s
    zCmfGanttTask._get_calendarc             C   s   d }d }dddg}| j |d}x|D ]}|  |j| jjdd|_d |_|jjr\|  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$W | jr| jr| jrd | _| 	  n$|r|| _|r|| _| jdd	 d S )
NrL   z!=T)r0   )rP   rQ   )r|   )r   )rP   )ro   )r1   rk   rW   r   newr   r   ra   "_calc_sched_period_for_child_tasksr   _alert_changed_plan_fieldsr   rG   r\   r[   rX   rL   r	   rw   )r*   r   r   r0   child_tasks
child_taskr$   r$   r%   r     s@    






z/CmfGanttTask._calc_sched_period_for_child_tasksc             C   s   | j | jjd |   | jjrt| jjrt| jrj| j| jk rj| j| _td| jj d| jj	 d| jdd | 
  nFd }| jr| jr| jsd | _|   d}n| jdd	 d
}| j|d d S )N)rP   u/   Предупреждение: В задаче "z" (u2   ) дата начала перемещена на z%d.%m.%Yub   , так как была позже даты ограничения дочерней задачи.
start_dateT)rp   duration)changed_field)rW   r   r   rk   r   ra   ri   rO   rM   rN   r   r	   lock_sched_finish_dater   r   rw   _calc_resources)r*   r   r$   r$   r%   r     s    (
z,CmfGanttTask._do_sched_start_date_is_changedc             C   s|   | j | jjd |   d }| jrT| jsT|   d}| jjrd| jj	rd| jrd| 
  n| jdd d}| jjsx| j|d d S )N)rP   r   T)rp   r   )r   )rX   r   r   rk   r	   r   r   r   ra   ru   r   rw   r   )r*   r   r$   r$   r%    _do_sched_finish_date_is_changed(  s    
z-CmfGanttTask._do_sched_finish_date_is_changedr   )Z	only_onceZonly_once_argsc             C   sP   t jj| d}| }|| t jj||d}|jd||d |jdd d S )N)r   )r   r   T)deferredr   ignore_child_task)r   )r   r   r   r-   rY   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   sX  | j rf|rb|jr"| jr"|j| jk s:|jrb| jrb|j| jkrbd}t||jj|jj| jj| jj dS |dkrtt }| j	j
|krdS || j	j
 |s| jjdkrt| j| j	j
|j	j
|dd dS d}d}|s|nd}|s|nd}	ddddgd	ddgg}
| j|
d
}x|D ]}|r(|j	|j	kr(q|jr\|s<|}n |jsJ|}n|j|jkr\|}|jr|	sp|}	n |	js~|}	n|	j|jk r|}	qW |r|j}|	r|	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|rd|jj d|jj d}| jj
}| jdkrf||krfd|d}nL| jdkr||k rd|d}n(| jdkr||krd|d}nd}d}| jrV|rVd|	jj d|	jj d}| jj
}| jdkr
||kr
d|d}nL| jdkr.||k r.d|d}n(| jdkrR||krRd|d}nd}|r|pd|}td| jj d| jj d| d| d	dd || _|| _| jjs| jjr| jdd  |s|r| j|jk r|j| _| jdd  |  }|rTt J xB|D ]:}||   |j| ||d! |  |jd"dd# qW W dQ R X dS )$u  
        Обновляет плановые даты родительской задачи.
        Плановая дата начала = самая ранняя плановая дата начала всех подзадач
        Плановая дата окончания = самая поздняя плановая дата окончания всех подзадач

        Args:
            child_task (optional): Defaults to None
                измененная дочерняя задача, которая еще не сохранена.
            ignore_child_task (bool, optional): Defaults to False
                игнорировать дочернюю задачу при обновлении дат родительской задачи.
        u   Задача "{}" ({}) вышла за диапазон плановых дат родительской задачи "{}" ({})Nztask.gantt_project)r   r   r   )kwargsORr   z!=r   )r0   "z" ()z0-constu(   Фиксированное начало z%d.%m.%Yz3-afteru   Начало не раньше z4-beforeu   Начало не позже u.   Фиксированное окончание z1-afteru%   Окончание не раньше z2-beforeu#   Окончание не позже uU   Конфликт планирования: В родительской задаче "u   ) ограничение "u<   " конфликтует с дочерней задачей rJ   T)rK   )ro   )r   pathF)
user_inputr   ) rL   r   r   rO   formatr   rM   rN   setr   rG   addr.   schedule_deferred_jobr   r1   r   r   r   r   ru   rw   r	   rv   r   r   disable_aclrY   r-   r   r   r   )r*   r   r   r   r   msgZmin_start_dateZmax_finish_datesZchild_task_with_min_startZchild_task_with_max_finishr0   Zgantt_tasksr!   rU   Zconflict_child_task_min_startr   Zconflict_child_task_max_finishr   Zconflict_child_taskr   r]   r$   r$   r%   r   G  s    $








&

z,CmfGanttTask.from_sched_dates_of_child_tasksc          	   C   sx   |   }|rtt Z t }|| jj x>|D ]6}|jj|kr0|j| ||d |  |j	ddd q0W W dQ R X dS )uq  
        Обновление дат начала и окончания родительской задачи и доп родительских задач.
        Передает дочернюю задачу (self), так как она еще не сохранена
        и родительская задача не может получить обновленные данные.

        Args:
            ignore_child_task (bool, optional): Defaults to False
                игнорировать дочернюю задачу при обновлении дат родительской задачи.
        )r   r   FT)r   r   N)
r   r   r   r   r   r   rG   r   r   r   )r*   r   r   r   r!   r$   r$   r%   update_parent_task_sched_dates  s    


z+CmfGanttTask.update_parent_task_sched_datesc             C   s   |   }x|D ]}|jdkr&td q| | r|| rF| | || 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W d S )Nz0-constu^   Дата родительской задачи является зафиксированнойz4-beforeu   Предупреждение: Плановая дата начала дочерней задачи больше плановой даты начала родительской задачиz3-afteru   Предупреждение: Плановая дата начала дочерней задачи меньше плановой даты начала родительской задачи)
date_field)r   r   rO   r   _change_parent_start_date)r*   r   parentsr]   r$   r$   r%   r     s"    

 z&CmfGanttTask._change_parent_start_datec             C   s   |   }x|D ]}|jdkr&td q| | r|| rF| | || 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W | jdk| _d S )Nz0-constu^   Дата родительской задачи является зафиксированнойz1-afteru   Предупреждение: Плановая дата окончания дочерней задачи меньше плановой даты окончания родительской задачиz2-beforeu   Предупреждение: Плановая дата окончания дочерней задачи больше плановой даты окончания родительской задачи)r   r   rO   r   r   _change_parent_finish_dater   r   )r*   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jr| j
rH| jj| j
k r| jr`| jj| jkr| jst| jj| _n\| jdkrnN| jdkr| jj| jkr| jj| _n&| jdkr| jj| jk r| jj| _| jdk| _| jr| jjr| jr| jdkr
| jsd | _|   | jrL| jjrL| jdkr>| jsDd | _|   | jdd	 d S )
N)z0-constz1-afterz2-beforez0-constz1-afterz2-beforeu   Нельзя указать Дату окончания больше зафиксированной у родительской задачиT)rK   u   Нельзя указать Дату окончания меньше зафиксированной у дочерней задачи)r   )rk   r   r   r   rj   r[   r\   rg   r   ri   rh   rO   r   Zplan_end_dater   ru   r	   r   r   r   r   r   )r*   r   r$   r$   r%   $_do_constrain_finish_date_is_changed.  sf    







z1CmfGanttTask._do_constrain_finish_date_is_changedc             C   sz   | j dkrB| jdkrB| jjsB| jjsB|r6tddd ntddd |sv|sb| jrVd | _| jdd |sv|sv| j	dd d S )	Nz0-constu  Конфликт планирования: невозможно изменить трудозатраты, если установлена опция "Фиксированные Ресурсы" и зафиксированы даты начала и окончания.T)rK   u   Конфликт планирования: невозможно изменить длительность, если зафиксированы даты начала и окончания.)r|   r   )r   )
r   r   r   ru   r   rO   r   r   r   r   )r*   Zfrom_sched_work_changedrp   rn   ro   from_calc_resourcesr$   r$   r%   rv   t  s    
z*CmfGanttTask._do_sched_duration_is_changedc             C   s   |    d S )N)r   )r*   r$   r$   r%   _do_actual_duration_is_changed  s    z+CmfGanttTask._do_actual_duration_is_changedc          	   C   s   | j jrd S | j dk r"tddd | jjs>| jjdkr>| j | _|   | j jpPd| j j	pZd }| 
 r| jjdkrt 2 | 
 }||   || |jdd W d Q R X |s| jjrtj| j| d S )Nr   uo   "Фактические трудозатраты" стал ниже нуля, выставляем в ноль.T)rK   ztask.gantt_projectF)r   )r   r6   rO   r   ra   r.   actual_myself_workr   r   rt   r+   r   r   rY   r-   from_child_add_workr   ru   r   ZCmfTimeTrackerZ"_op_gantt_actual_work_changed_hook)r*   from_timetracker
work_deltar]   r$   r$   r%   _do_actual_work_is_changed  s     


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 d Q R X d S )
Nr   ue   "Фактические Затраты" стал ниже нуля, выставляем в ноль.T)rK   z3-costr4   ztask.gantt_projectF)r   )actual_costr6   rO   r   r
   r   r   r   r\   r   r   r+   r   r.   r   rt   r   r   rY   r-   from_child_add_costr   )r*   r   
cost_deltar]   r$   r$   r%   _do_actual_cost_is_changed  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 )Nz0-workz3-cost)r   r6   r   )r*   r$   r$   r%   _do_actual_complete_is_changed  s    

z+CmfGanttTask._do_actual_complete_is_changedc             C   sH   | j jp
d| j jpd }| jjs*| j | _n|  j|7  _| j|d d S )Nr   )r   )r   r   rt   r   ra   r   r   )r*   r   r   r$   r$   r%   !_do_actual_myself_work_is_changed  s
    
z.CmfGanttTask._do_actual_myself_work_is_changedc             C   sD   | j jp
d| j jpd }| jjs*| j | _n|  j|7  _|   d S )Nr   )actual_myself_costr   rt   r   ra   r   r   )r*   r   r$   r$   r%   !_do_actual_myself_cost_is_changed  s
    
z.CmfGanttTask._do_actual_myself_cost_is_changedc       	   	   C   sV  | j jrd S | j| j kr(| j | _|   | 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
 | 	  | 
 r4| jjdkr4| j jpd| j jpd }t < | 
 }||   || |  |jddd W d Q R X |sR|sR|sR| jdd d S )N<   u   ч u   мu   Нельзя запланировать меньше Трудозатрат, чем запланировано в подзадачах (z < ub   ). Увеличьте Трудозатраты или уменьшите их у подзадач.T)rK   u   DEV: Указано Трудозатрат меньше, чем запланировано в подзадачах. Выставили uo   . Если нужно уменьшить Трудозатраты, уменьшите их у подзадач.ztask.gantt_projectr   F)r   r   work)r   )r   r6   r   %_do_timetracker_sched_work_is_changedr   ra   agregat_work
const_workrO   r   r+   r.   r   rt   r   r   rY   r-   from_child_agregate_workr   r   r   )	r*   Zfrom_sched_duration_changedro   rp   r   r   r   r   r]   r$   r$   r%   _do_sched_work_is_changed	  s4    


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 d Q R X d S )Nu   Нельзя запланировать меньше Расходов, чем запланировано в подзадачах (z < uX   ). Увеличьте Расходы или уменьшите их у подзадач.T)rK   u|   Указано Расходов меньше, чем запланировано в подзадачах. Выставили ue   . Если нужно уменьшить Расходы, уменьшите их у подзадач.ztask.gantt_projectr   F)r   r   )r
   r6   agregat_cost
const_costrO   r+   r   r.   r   rt   r   r   rY   r-   from_child_agregate_costr   r   )r*   r   r]   r$   r$   r%   _do_sched_cost_is_changedF  s     


z&CmfGanttTask._do_sched_cost_is_changedc             C   s"   | j r| jr|   n|   d S )N)rx   rz   r   r{   )r*   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 )N)rx   ry   rz   r   r{   )r*   r$   r$   r%   !_do_actual_finish_date_is_changedc  s    
z.CmfGanttTask._do_actual_finish_date_is_changedc             C   sZ   | j dkr|   nB| j dkr0| jjr0|   n&| j dkrD|   n| j dkrV|   d S )Nz0-work)z
1-completez2-story_pointsz3-costz5-timetracker)r   r   r   ra   r   r   r   )r*   r$   r$   r%   #_do_actual_complete_type_is_changedi  s    





z0CmfGanttTask._do_actual_complete_type_is_changedc             C   s:   | j r|   n&| jjr(| jd dd nd| _|   d S )NT)r   r   z1-early)rL   rw   r   ra   r   r   r   )r*   r$   r$   r%   _do_const_duration_is_changedw  s    
z*CmfGanttTask._do_const_duration_is_changedc             C   s*   | j rd| _| j| _n| jj| _d | _d S )Nz0-const)r   r   r   r   default)r*   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 )Nz0-const)r   r   r   r   r   )r*   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r| j|jjdd| _| jjr|   n
||  |jdd d S )Nr
   r   r   r   T)rP   rQ   )r   )rY   r"   r'   r-   r   r
   r   r   r   r   r   r   rL   rW   r   rG   ru   r   r   r   )r*   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 |j }| |   || j  || j  || j	  |
| j  |j| dd |jdd d S )Nr
   r   r   r   T)r   )r   )rY   r"   r'   r-   r   r
   r   r   r   r   r   r   r   r   )r*   r   r]   r$   r$   r%   "remove_child_task_from_parent_task  s    
z/CmfGanttTask.remove_child_task_from_parent_taskc          	   C   sP   t  > | jjp| j}|r&| | | jjp2| j}|rB| | W d Q R X d S )N)r   r   r   rt   r   r   r   r   )r*   Z
old_parentZ
new_parentr$   r$   r%   _do_parent_task_is_changed  s    

z'CmfGanttTask._do_parent_task_is_changedc             O   s   t jj| df|| d S )Nupdated)r   ZCmfEventZdo_event)r*   argsr   r$   r$   r%   _do_event_save  s    zCmfGanttTask._do_event_savec             O   s
   | | j S )N)Z	log_level)r*   
field_namer   r   r$   r$   r%   _get_field_log_level  s    z!CmfGanttTask._get_field_log_levelc             C   s  | j rTd| _d| _|  rP|  }|j }|rBt|tj	 | _d| _
|   d S | j
jrbd| _
| jjrv|   d S | jjr|   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r4|   |s0|   d S | jjrJ|    d S | j!jr`| "  d S | j#jrv| $  d S | j%jr| &  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r0| .  |s,|   d S | j/jrF| 0  d S | j1jr\| 2  d S | j3jrn| 4  | j5jr| 6  d S )Nr   z1-early)7is_newr	   r   r+   r   r'   r[   rB   rE   Zutcnowr   r   r6   r   ru   r   r   r   r   r   rv   r   rz   r   r   r   r   r   r   r   r   r
   r   rx   r   ry   r   r   r   r   r   r   r   r   r   r   r   rL   r   r   r   r   r   r   r   )r*   from_parent_changesr]   r   r$   r$   r%   _save  s    












zCmfGanttTask._savec              C   s  |sd S t d| j  |d kr@tjjdd| jgdddgd}t|}|dkrTd S x`|D ]X}dd|jgdd|j	gd	dd
gg}x2tj
j|dD ] }t  |  W d Q R X qW qZW | jr| jr| jjrd S | jj}d }| jr| jj}| jj}	| jj}
|
}d}|	s|
sd S |
s|	}
|	s$|
}	| jj}| jj}| jj}|rZ|dkr|
|	 | }nT|r|dkrx|
|	 | }n|dks|dkr|	| }
n|r|dkr|	| }
|
}d}|dkr|
| }|
| }g }g }i }x|D ]}|}|dkr||7 }d}d }d }x8|jj| | jj|o.| dD ]}|jj}d}|| kr^||}|jj| }|dkrxq4t|| |k rt|| n|}||}||t||  p|jddd}tj
|j| j||d
|dd}t  |  W d Q R X |s|}| |d}||kr*|||< ||8 }|dkr4|}P q4W |!| |!| | |_"| |_#t|d |_$t  |  W d Q R X qW t%|| _t&|| _tt'|( | | _|
| _|r|dkrv|	| jjkrv| j)dd nz|r(|dkrv|| jjkrv| j*dd nN|rv|dkrR|	| jjkrR| j)dd |dkrv|| jjkrv| j*dd t d| j  d S )Nz&_calc_resources start. gantt_task_id: r   z==personrH   )r,   r   r   	cmf_ownerhistory_typeZplan)r,   rl   r   r   units)r   rm   finish_date   ;   )hourminute)r   r   r   Zend_dater   Z
time_spentremaining_estimater4   )r   r   T)r   )r   r   z'_calc_resources finish. gantt_task_id: )+gdebugr   r   rq   r/   r   r   r   r   ZCmfTimeTrackerHistoryr   r   deleter   r	   ra   rG   r   r   const_resourcer   rL   rH   Z	work_daysZdateZget_work_time_shiftZinterval_total_minutesr=   Zget_shifted_work_timereplacer   r   r   Z
date_startZdate_endr   r\   r[   sumvaluesrv   r   ) r*   r   assignmentsZnumber_of_resourcesZ
assignmentr   Ztthr   r   r   r   Zinitial_workr   r  r   rL   Zwork_per_personZwork_remainderZstart_timesZ	end_timesZmax_work_per_dayZ	work_leftZ
start_timeZend_timeZdayZcur_dateZ
time_shiftZ
avail_timeZwork_for_todayZtth_start_dateZtth_end_dateZcur_max_work_for_todayr$   r$   r%   r   +  s    











"
&













zCmfGanttTask._calc_resourcesc             C   s4   |  |   |   | jd|d | jdd d S )Nr   )r   r  T)r   )rY   r-   r   r   r   )r*   r  r$   r$   r%   task_resources_changed_hook  s    z(CmfGanttTask.task_resources_changed_hookc             C   sT   |  |   |   |  j|7  _|d kr8| j| | _| jdd | jdd d S )NT)r   )r   )rY   r-   r   r   r   r   r   )r*   r   r   r$   r$   r%   timetracker_add_work_hook  s    	z&CmfGanttTask.timetracker_add_work_hookc             C   sT   |  |  dg  | jrP| jj| _| jsD| | jj | | j | jdd d S )Nztask.gantt_projectT)r   )	rY   r-   r   r   r   r   rt   r   r   )r*   r$   r$   r%   task_parent_is_changed_hook  s    
z(CmfGanttTask.task_parent_is_changed_hookc             C   s   |    d S )N)r   )r*   r$   r$   r%   r     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_PROGRESST)r   r   r4   r   )r   rx   rY   r-   r   Zset_nowr   r   ry   r   r   r   r   )r*   Z
old_statusZ
new_statusr$   r$   r%   task_status_is_changed_hook  s:    

z(CmfGanttTask.task_status_is_changed_hookc             C   sP   |  |   | js tddd |   |   |   |   | jdd dS )u   
        В задаче изменились Agile-плановые даты, пересчитаем свои sched-даты, вдруг новые ограничения повлияют на них
        u?   У гант-задачи нет ссылки на задачу.T)rK   )r   N)	rY   r-   r   rO   r   r   r   check_gantt_projectr   )r*   r$   r$   r%   task_plan_dates_is_changed_hook  s    z,CmfGanttTask.task_plan_dates_is_changed_hookc             C   s    | j jrd| _ |  j |7  _ d S )Nr   )r   r6   )r*   r   r$   r$   r%   r     s    z CmfGanttTask.from_child_add_workc             C   s    | j jrd| _ |  j |7  _ d S )Nr   )r   r6   )r*   r   r$   r$   r%   r   "  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 d Q R X d S )Nr   r   u   ч u   мu;   Превысили План на Трудозатраты (z <= u+   ) в родительской задаче ub   . Увеличьте в ней план или введите меньше Трудозатрат.T)rK   ztask.gantt_projectF)r   r   )r   r6   r   r   r   rt   rO   r   r+   r.   r   r   rY   r-   r   r   r   )r*   r   r   r   r]   r$   r$   r%   r   '  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 d Q R X d S )Nr   u1   Превысили План на Расходы (z <= u+   ) в родительской задаче u[   . Увеличьте в ней план или введите меньше РасходовT)rK   ztask.gantt_projectF)r   )r   r6   r   r
   rO   r   r+   r.   r   rt   r   r   rY   r-   r   r   )r*   r   r]   r$   r$   r%   r   A  s    


z%CmfGanttTask.from_child_agregate_costc             C   s   |  | dS )u   
        Оповестить родителя, что ему нужно пересчитать свой агрегат actual_complete
        N)r   )r*   r   r$   r$   r%   !from_child_update_actual_completeU  s    z.CmfGanttTask.from_child_update_actual_completec          	   C   sP   |   sdS t 2 |   }||   ||  |jdd W dQ R X dS )uP  
        Оповещение родителя.
        Передаем себя, т.к. мы еще можем быть не сохранены и родитель не сможет получить наши данные
        Другой вариант: опочещать через отдельный таск в celery
        NF)r   )r+   r   r   rY   r-   r  r   )r*   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rz| jjrzt	ddd | j
jr| j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js| jdkrt	ddd d S )Nc             S   s   h | ]\}}|qS r$   r$   )r   k_r$   r$   r%   	<setcomp>n  s    z0CmfGanttTask.check_user_input.<locals>.<setcomp>T)ru   r   Zparent_task_idr   Zgantt_project_idzPPP-TSK-SCHEDULE)obju   Нельзя менять поле "Фактические трудозатраты" у Summary-задач. Используйте поле "Фактические трудозатраты по собственным ресурсам задачи")rK   u   Нельзя менять поле "Фактические Затраты" у Summary-задач. Используйте поле "Фактические Затраты по собственным ресурсам задачи"u\   Нельзя выставить Дату начала позже Даты окончания)z
1-completez2-story_pointsu   Этот вариант рассчета процента завершения можно использовать только у Summary-задач)r   ru   itemsr   r   r'   Zcheck_project_role_accessr   ra   rO   r   r   r   r   )r*   Zchanged_fieldsr$   r$   r%   check_user_inputl  s*    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| _d S )Nr   )r   r6   r   r
   r   r	   rz   r   r   r   r   Zconstrain_slackZconstrain_slack_pct)r*   r$   r$   r%   r     s0    zCmfGanttTask.fix_null_variablesr   c             C   sL  t d| j d|  | jjdkr(d S | jsH|sX|sX| jsX| jsX| jsX| j	sX| j
rH| j  | jj| _| jjdd |s| jjr|  }x<|D ]4}|jr|j| jkr|jd|d d |jdd qW |s4|  r4|  }||   |jjdkr4|jr|j| jkr4|jd|d d |jdd | jsH| | j d S )	Nz!check_gantt_project: gantt_task: z	, level: ztask.gantt_projectT)r   rl   )r   level)ro   r  )r   r   r   r   r.   r   r   r   r	   r   r
   Z_calc_gantt_projectr   ra   r1   r
  r+   rY   r-   r   r   )r*   r   ro   r  r   r   r]   r$   r$   r%   r
    s<    



z CmfGanttTask.check_gantt_project)r   r   from_sort_orderc               s   |r|    | j|| | j|d | jjr:| jjdd |   |   t j||}|s| j	jrdd| jgdddgg}t
jj|drtt
jj| jjgd	 |S )
N)r   T)r   r   z==zrelation_type.codezsystem.finish:start)r,   )r   )r  r   r   r   ru   r   r
  r   r2   r   r   r   rr   r   Zsort_task_by_order_relationsr   )r*   r   r   r  r   r   r:   r   )r3   r$   r%   r     s    zCmfGanttTask.save)TEXKOM_db_deletec               s   |  dddg |rZt| j x^tjj| jddD ] }t| d |_|jdd q4W n&| j	r| j	j| kr| j	j
stddd | j	r| j	j| kr| | j t j|d	|i|S )
Nztask.op_gantt_taskztask.cmf_deletedr   T)r"   Zinclude_deleted)r   uY   Нельзя удалять Оперативную гант задачу у задачи!)rK   r  )rY   r   r   r   r   r   r/   r"   r   r   Zcmf_deletedrO   r   r   r2   r   )r*   r  r   r   r   )r3   r$   r%   r     s    
zCmfGanttTask.deletec                sB   t  jf | | jrd S td tj| jdd td d S )Nz_CmfAutomationCrudTrigger startupdateZbefore_savez_CmfAutomationCrudTrigger end)	r2   before_save_hookr   r   r   r   CmfAutomationCrudTrigger	crud_hookr   )r*   r   )r3   r$   r%   r    s    
zCmfGanttTask.before_save_hookc                sB   t  jf | | jrd S td tj| jdd td d S )Nz_CmfAutomationCrudTrigger startr  Z
after_savez_CmfAutomationCrudTrigger end)	r2   before_save_data_hookr   r   r   r   r  r  r   )r*   r   )r3   r$   r%   r    s    
z"CmfGanttTask.before_save_data_hookr  c          	   C   sv   | j   tjr| j sd S tjtjjjdg|| jj| jddtj| j jjd}t	d|d  ||d |d gd d S )Nproject_notifyT)ru   )ZinitiatorSessionTabIdZinitiatorCurrentPersonactionZinitiatorActionZinitiatorObjIdZinitiatorObjChangedFieldsu   initiatorСomponentId	projectIdzproject_notify-r  )ZroomZevent_persons)
r   r'   r   Zsession_tab_idZcurrent_personr   rG   keysZcomponent_idZcmf_emit_event)r*   Zinitiator_actionZeventr$   r$   r%   r    s    

zCmfGanttTask.project_notifyc             C   s  | j jdkrd S ddddd}d }x| 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rz|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| }|rv|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.W d S )Nztask.gantt_projectu)   Плановая длительностьu)   Плановые трудозатратыu&   Плановая дата началаu,   Плановая дата окончания)r	   r   r   r   )r	   r   u   Нетr   Z02du   ч u   мин)r   r   )r@   zUTC z+03d:z%Y.%m.%d, %H:%M u   DEV: У задачи z (u   ) изменено поле "z":                        c u    на rJ   u.   ) сброшено значение поля "z".)r   r.   r  rf   ru   r   rt   rA   Z
astimezoner   rB   rD   rC   rG   divmodZstrftimerO   rM   rN   )r*   r   rH   r   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   ,  sJ    

Dz'CmfGanttTask._alert_changed_plan_fields)N)NF)NF)FF)F)F)F)N)NFNF)F)FFFFF)F)F)FFFF)N)N)F)NN)N)N)FFr   )r  )W__name__
__module____qualname__Z	api_allowclassmethodr&   r)   r(   r+   r1   r-   propertyr;   r>   r?   r7   rW   rX   rZ   rd   rk   rw   r{   r}   r~   r   r   r   r   r   r   rA   r   r   r   staticmethodZcmf_deferred_jobr   r   r   r   r   r   rv   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   r  r   r
  r   r   r  r  r  r   __classcell__r$   r$   )r3   r%   r      s   
&
'+_

"	


%
DF	1
 
F  
1
#


 
<


^
 
'

* 


r   )rE   rB   Zdateutil.tzr   decimalr   r   r   Z
cmf.fieldsZcmf.includeZ#modules.gantt.fields.cmf_gantt_taskr   r$   r$   r$   r%   <module>   s   