U
    ĮwhK                     @   s>   d dl T d dlmZ d dlmZmZmZ G dd dejZdS )    )*)cmf_relation_option)defaultdictdeque
namedtuplec                       s   e Zd ZdZ fddZ fddZeedddgdd	d
d'ddZdd Z	dd Z
edddZdd Z fddZdd Zdd Zd(dd Zd!d" Zd#d$ Zed)d%d&Z  ZS )*CmfRelationOptionuN    Класс для соединения задач и типов связей c              
      s\  t j| dd | j| jkr(tddd dd| jgdd	| jgd
d	| jgdd	| jgg}t jj	|drntddd | j
jdkrt jj	dd	dgd
d| j| jggdd| j| jgggdrtddd | ddddg |  rtddd | j
jdkr|  rtddd | j
jdkr| ddddddddg | jj| jksP| jj| jkr\td dd |  rrtd!dd t jj	dddd"ggd
d| j| jggdd| j| jgggdrtd#dd |   t j||}t j| dd$ | j
jdkr| jj  | j
jdkrL| js| jjrL| jjjrL| jjjrLtt jj| jjd%d&d' t j|  |S )(Nupdatebefore_saveuV   Внимание! Нельзя связывать задачу саму с собой!Tabortidz!=out_link==in_linkrelation_type_idfilteru2   Такая связь уже существует.)system.finish:startsystem.finish:finishrelation_type.codesystem.additional_parentINu   Невозможно связать задачи связью ОО/ОН, так как они связаны связью Дополнительный родитель/Дополнительная дочерняя задача.+in_link.parent_task.cache_branch_gantt_pathz,out_link.parent_task.cache_branch_gantt_pathz'out_link.op_gantt_task.sched_start_datez(out_link.op_gantt_task.sched_finish_dateum   Невозможно связать суммарную задачу с одной из ее подзадач.r   u   Невозможно связать задачи, так как они уже связаны через другую последовательность задач.in_link.op_gantt_taskout_link.op_gantt_taskz out_link.cache_branch_gantt_pathzout_link.has_child_taskszin_link.cache_branch_gantt_pathin_link.has_child_tasksu  Невозможно связать задачи связью Дополнительный родитель/Дополнительная дочерняя задача, так как они являются родительской и дочерней задачами.u  Невозможно связать задачи связью Дополнительный родитель/Дополнительная дочерняя задача, так как они связаны через другую последовательность задач.r   u   Невозможно связать задачи связью Дополнительный родитель/Дополнительная дочерняя задача, так как они связаны связью ОО/ОН.
after_savecreate)task_idaction)kwargs)modelsCmfAutomationCrudTrigger	crud_hookr   r   	cmf_alertr   r   r   sgetrelation_typecodeload_fieldshas_parent_child_relationshas_start_finish_loopparent_taskhas_additional_parent_loop'_check_additional_parent_task_relationssupersaveop_gantt_task*additional_children_relations_changed_hookZis_newconstrain_lagZ
is_changedsched_start_datesched_finish_dateZschedule_deferred_jobsort_task_by_order_relationsCmfBackbonePeerZobj_after_save_hook)selfargsr    Zduplicate_filterres	__class__ ,./modules/task/models/cmf_relation_option.pyr/   
   s    



 
 
 
 zCmfRelationOption.savec                    sn   t j| dd | dg t j||}| jjdkrN| dg | jj	
  t j| dd t j|  |S )Ndeleter	   r&   r   r   r   )r!   r"   r#   r(   r.   r>   r&   r'   r   r0   r1   r6   Zobj_after_delete_hook)r7   r8   r    r9   r:   r<   r=   r>   R   s    zCmfRelationOption.deleteTr      uc   Вычисление плановых дат у задач от выставленной связи)Z	only_onceZshow_bg_progressbarZonly_once_argsprioritydescriptionNr   c              
   C   s  | d krd S |st  }| |kr"d S ||  tjjdd| gdddgd}|sPd S td|jj d|j	j d	|j
j d
|  |j
j}|sd S tjjdddgdd|ggdddgd}|D ]}|j}|j
}	|	|	  |	jr|dkr|dksqt|jjpd}
||	jkr|j}|
r,|jj}tj|||
}|	j|dd}||	_|	 }|rPq|	jdd |d rlt  tjj|jj||d d qd S )Nr   r   r0   zop_gantt_task.sched_finish_datezproject.calendar.timezoner   Zfieldsz,sort_task_by_order_relations start task_id: z (z), sched_finish_date z	, depth: r   r   r   r   r   r2   r   r   T)Zreturn_correct_date)Zfrom_sort_order
   r?   )pathdepth)setaddr!   CmfTaskgetgdebugnamevaluer'   r0   r4   r   listr   r(   save_preload_fieldsZ	is_manualintr2   r3   projectcalendarZCmfCalendarZget_date_by_durationZcheck_correct_start_dateZ _get_task_blocking_back_movementr/   Z
cmf_commitr5   r   )r   r   rD   rE   taskZtask_finish_dateZfollowing_linksZfollowing_linkZfollowing_taskZfollowing_gantt_taskr2   Znew_start_daterR   Zblocking_taskr<   r<   r=   r5   c   s^    
.

z.CmfRelationOption.sort_task_by_order_relationsc                 C   sp   | j }| j}t }|jr,|dd |jD B }|jr`|jjrP|dd |jjD B }||jjj |j|d d S )Nc                 S   s   h | ]}|d  qS r   r<   .0tr<   r<   r=   	<setcomp>   s     zLCmfRelationOption._check_additional_parent_task_relations.<locals>.<setcomp>c                 S   s   h | ]}|d  qS rT   r<   rU   r<   r<   r=   rX      s     )Z
gantt_path)	r   r   rF   cache_branch_gantt_pathr+   rG   r   rM   Z_check_additional_relations)r7   Z
add_parentZ	add_childZadd_parent_gantt_pathr<   r<   r=   r-      s    z9CmfRelationOption._check_additional_parent_task_relationsc                    s:   t j \}t t  fdd  | jjjS )Nc                    sd   | krdS | krdS  |   |  | g D ]\}} |}|r8|  S q8|  dS NTF)rG   rI   remove)nodeneighbor_resultdfs	stack_settask_out_linksvisitedr<   r=   ra      s    



z4CmfRelationOption.has_start_finish_loop.<locals>.dfs)r!   r   get_start_finish_graphsrF   r   op_gantt_task_idrM   )r7   r^   r<   r`   r=   r*      s
    z'CmfRelationOption.has_start_finish_loop)returnc                    sN   t jjdddgdjd
 fdd	  fdd	}|| j| jpL|| j| jS )u   
        Проверяет, что связанные задачи не находятся друг у друга в родителях
        r'   r   r   r   r   c                    s   |dkrt ddd t }ddgdd| gg}dd	g}tjj||d
D ]N}|j}|jr|jjrz|jjD ]}||d  qf||jj	 ||j	 qFt }|D ]"}	 |	|d d}
|
r|
|
 q|
| |S )Nd   ui   DEV: Защита от рекурсии: cmf_realtion_option.has_parent_child_relations: if r_count > 100Tr
   r   r   Zout_link_idr   r   rB   r   r?   )r_count)r$   rF   r!   r   slistr   r+   rY   rG   r   r   )r   ri   additional_parent_ids_filter_fieldsrelZadd_parent_taskrW   Zsub_additional_parent_idsr   additional_ids_add_additional_parent_idsZadditonal_parent_type_idr<   r=   rq      s0    
zPCmfRelationOption.has_parent_child_relations.<locals>._add_additional_parent_idsc                    s   t |jjg}|jrH||jjj |jjrH|jjD ]}||d  q4t  }|D ]} |}|rR|| qR|| | jj|kS )Nr   )rF   r   rM   r+   rG   rY   r   )childparentZparent_task_idsrW   Zadditional_parent_task_idsr   ro   )rq   r<   r=   _find_in_parents   s    
zFCmfRelationOption.has_parent_child_relations.<locals>._find_in_parents)r   )r!   ZCmfRelationTyper%   r   r   r   )r7   rt   r<   rp   r=   r)      s     z,CmfRelationOption.has_parent_child_relationsc                    s6   t  t  dd  fdd  | jjjjS )Nc                 S   sz   g }t jjdd| gdgd}|r4|jr4||jj dd| gdddgg}t jj|d	gd}|rvd
d |D }|| |S )Nrf   r   zparent_task.op_gantt_task_idrB   zout_link.op_gantt_task_id=r   r   zin_link.op_gantt_task_idc                 S   s   g | ]}|j jqS r<   )r   rf   )rV   rn   r<   r<   r=   
<listcomp>  s     zXCmfRelationOption.has_additional_parent_loop.<locals>.get_parent_ids.<locals>.<listcomp>)	r!   rH   r%   r+   appendrf   r   rj   extend)gantt_task_idZ
parent_idsrS   rl   Zadditional_parents_relationsrk   r<   r<   r=   get_parent_ids
  s    

zDCmfRelationOption.has_additional_parent_loop.<locals>.get_parent_idsc                    s\   | krdS | krdS  |   |  | D ]} |}|r4|  S q4|  dS rZ   )rG   r[   )r\   r]   r_   ra   rz   rb   rd   r<   r=   ra     s    



z9CmfRelationOption.has_additional_parent_loop.<locals>.dfs)rF   r   r0   r   rM   r7   r<   r{   r=   r,     s
    z,CmfRelationOption.has_additional_parent_loopc                    s   t   dddg S )Nr&   zout_link.project_idzin_link.project_id)r.   rO   r|   r:   r<   r=   rO   1  s    z%CmfRelationOption.save_preload_fieldsc                 C   sV   |  ddg | jr0| jjr0| jjjd| jd | jrR| jjrR| jjjd| jd d S Nzout_link.projectzin_link.projectzPPP-TSK-LINK)objr(   r   rQ   Zcheck_project_role_accessr   r|   r<   r<   r=   check_edit_perm4  s
    z!CmfRelationOption.check_edit_permc                 C   sV   |  ddg | jr0| jjr0| jjjd| jd | jrR| jjrR| jjjd| jd d S r}   r   r|   r<   r<   r=   check_delete_perm<  s
    z#CmfRelationOption.check_delete_permr   c              	   C   s
  |  ddg tjsd S | jr| jjr| jjjjdkrtjtjjjdgd| jjjdgtj	| jjjjd}t
d|d	  ||d	 |d	 gd
 | jr| jjr| jjjjdkrtjtjjjdgd| jjjdgtj	| jjjjd}t
d|d	  ||d	 |d	 gd
 d S )Nzout_link.parent.idzin_link.parent.idZ
CmfProjectproject_notifyr   Zin_tasks)ZinitiatorSessionTabIdZinitiatorCurrentPersonr   ZinitiatorActionZinitiatorObjIdZinitiatorObjChangedFieldsu   initiatorСomponentId	projectIdzproject_notify-r   )ZroomZevent_personsZ	out_tasks)r(   rJ   Zsession_tab_idr   rs   rM   
class_nameZcurrent_personr   Zcomponent_idZcmf_emit_eventr   )r7   Zinitiator_actionZeventr<   r<   r=   r   C  s4    

$$

z CmfRelationOption.project_notifyc                 O   s   t jj| df|| d S )Nupdatedr!   ZCmfEventZdo_eventr7   r8   r    r<   r<   r=   _do_event_saved  s    z CmfRelationOption._do_event_savec                 O   s   t jj| df|| d S )NZdeletedr   r   r<   r<   r=   _do_event_deletedi  s    z#CmfRelationOption._do_event_deletedc                    s    fdd}t tt t dddg}dddggg}tjj||d	D ]<}|jj |jj|j	f  |jj |jj|j	f qF| r|| S  fS )
Nc                    s~   t | }t }t }t }|rv| }| ||<  | ||< || || ||  D ]\}}||krX|| qXq||fS )N)r   rF   dictpopleftrG   rw   )ry   qZdoneZfiltered_task_out_linksZfiltered_task_in_linksZcurelr^   Ztask_in_linksrc   r<   r=   _filter_by_gantt_task_ido  s    
zKCmfRelationOption.get_start_finish_graphs.<locals>._filter_by_gantt_task_idr   r   r2   r   r   r   rB   )
r   rN   r!   r   rj   r   rf   rw   r   r2   )ry   r   Z
rel_fieldsZ
rel_filterrn   r<   r   r=   re   l  s    
z)CmfRelationOption.get_start_finish_graphs)NNNr   )r   )N)__name__
__module____qualname____doc__r/   r>   staticmethodZcmf_deferred_jobr5   r-   r*   boolr)   r,   rO   r   r   r   r   r   re   __classcell__r<   r<   r:   r=   r      s(   H:;,
!r   N)Zcmf.includeZmodules.task.fieldsr   collectionsr   r   r   r   r<   r<   r<   r=   <module>   s   