
    /i~R                     <   U d Z ddlmZ ddlmZmZ ddlZddlZddl	Z	ddl
Z
ddlZddlmZmZmZmZmZmZ ddl dedefd	Zdedefd
Zd ZdefdZd ZdedefdZ G d de      ZddddZeeef   ed<   dZdZ e G d d             Z!dede"fdZ#dedeeeef   fdZ$deded e%ddfd!Z&d"eded e%ddfd#Z'd$edeee   ee   f   fd%Z(ded&ee   deeee   ee!   f   fd'Z)ded(ee   deeee   ee!   f   fd)Z*ded(ee   deeee   ee!   f   fd*Z+ded(ee   deeee   ee!   f   fd+Z,ded&ee   deeee   ee!   f   fd,Z-ded&ee   defd-Z.ded.edee   fd/Z/dedefd0Z0ded1ee   d2ed e%de!f
d3Z1dejd                  d4fded&ee   d2ed e%de!f
d5Z3y)6u   
Утилиты для импорта объектов в EVA.
Содержит общие функции, используемые как CmfImportPlugin, так и CmfProjectImport.
    )	dataclass)EnumautoN)CallableOptionalDictAnyTupleList)*namereturnc                     g dg dddgg dd}|j                         D ]$  \  }}|D ]  }|| j                         v s|c c S  & y)N)u   открытopenu   к выполнениюtodonewpausedu
   зарегsubmit)u
   работprogressindeterminateactive
inProgressu   обсуждdiscusreviewu
   ревью)closeu   закрытu
   готовdonearchived	cancelled)OPENIN_PROGRESS	IN_REVIEWCLOSEDr   itemslower)r   mappingstatus_typewordswords        ./common/utils/import_utils.pycalc_status_typer+      sj    	

 


3!GF &mmo #U 	#Dtzz|#""	##
     c                     ddgddgg dg dg dd}|j                         D ]$  \  }}|D ]  }|| j                         v s|c c S  & y	)
u)   Поиск priority по синонимуu   минz-2u   низкz-1)u
   обычнu   нормальн0)u   срокu
   высок1)u   блокирующu
   большu   крит2)r         r   r#   )r   r&   priorityr(   r)   s        r*   calc_priorityr6   >   sf     t2*@G #==?  % 	 Dtzz|#	   r,   c                 Z    | sydddd}|j                  | j                               xs dS )Nr   r3   r2   )highnormallow)getr%   )priority_namesignificance_maps     r*   calc_significancer>   M   s<     
  3 3 56;!;r,   estimatec                    	 d}d| v r3| j                  d      }t        |d         dz  t        |d         z   }|S t        j                  d|       }t        j                  d|       }|r |t        |j	                  d            dz  z  }|r|t        |j	                  d            z  }|s|s| j                         rt        |       }|S #  t        d|        xY w)Nr   :<   r3   z(\d+)hz(\d+)muA   Неудалось преобразовать estimate_time из )splitintresearchgroupisdigitCmfImportError)r?   totalpartshms        r*   calc_estimate_timerN   X   s    m(?NN3'EaMB&U1X6E  		)X.A		)X.A%3qwwqz?R//%%3qwwqz?*% Q8#3#3#5Hm`ai`jklls   8C	 BC	 	Cc                 6   | r|syt        |       j                         j                         }|j                         D ]Y  \  }}|t        |      j                         j                         t        |      j                         j                         fv sW|c S  | S )ua  
    Находит ключ по значению или ключу в атрибуте choices у field
    Args:
        value: Значение для поиска
        choices: значения поля
    
    Returns:
        Найденный ключ или исходное значение, если ничего не найдено
    N)strstripr%   r$   )valuechoices	str_valuekeychoice_values        r*   calc_choicesrW   p   s     E
  "((*I %]]_ \\*00288:CHNN<L<R<R<TUUJ Lr,   c                     dgg ddgdgdgd}|j                         D ]$  \  }}|D ]  }|| j                         v s|c c S  & y)uc   Поиск программных типов workflow для проектов по синонимуagile)baseu   основнu   классическhelpdeskservicedeskwiki)project.agilezproject.basezproject.helpdeskzproject.servicedeskzproject.wikir^   r#   )r   r&   logic_prefixr(   r)   s        r*   calc_logic_typer`      sf     "H'L -G  '}} $e 	$Dtzz|###	$$ r,   c                   H    e Zd ZdZ e       Z e       Z e       Z e       Zy)
ImportModeu)   Режим импорта объекта.N)	__name__
__module____qualname____doc__r   CREATE_OR_UPDATECREATE_ONLYUPDATE_ONLY	FIND_ONLY r,   r*   rb   rb      s"    3v&K&KIr,   rb   
CmfProject	CmfPerson)parent	executors
spectatorsFIELD_MODEL_OVERRIDES)ext_idcodeemailloginr   )rr   rs   r   rt   ru   c                   0    e Zd ZU dZee   ed<   dZeed<   y)ImportResultNobjFis_new)	rc   rd   re   rx   r   r	   __annotations__ry   boolrk   r,   r*   rw   rw      s    C#FDr,   rw   
field_namec           	         t         j                  |       }|rJ|j                         D ]  }|j                  |k(  s|c S  t	        d| d|  d|j                                |j                         }|st	        d|  d      |d   S )uL   Определяет связанную модель для FK/M2M поля.u   Модель 'u:   ' не найдена среди related_models поля 'z': u
   Поле 'u    ' не имеет related_modelsr   )rq   r;   related_modelsrc   
ValueError)r|   
main_fieldoverride_namerM   relateds        r*   _resolve_related_modelr      s    )--j9M**, 	Azz]*	 ]O ,#C
(A(A(C'DF
 	
 '')G:j\1QRSS1:r,   
obj_fieldsc                    i }i }i }|j                         D ]  \  }}| j                  j                  |      }|xr< t        |t        j                  j
                        xr t        |t        t        f      }|s|||<   it        ||      }	t        |t        j                  j                        r	|	|d||<   |	|d||<    |||fS )u  
    Разделяет поля объекта на:
      - related_objs  (FK):  {field_name: {"model": ..., "fields": {...}}}
      - current_obj   (простые поля): {field_name: value}
      - m2m_objs      (M2M): {field_name: {"model": ..., "fields": [...]}}
    )modelfields)r$   r   r;   
issubclasscmf
CmfRelBase
isinstancedictlistr   
CmfM2MBase)
r   r   related_objscurrent_objm2m_objsr|   rR   r   is_relationrelated_models
             r*   _split_fieldsr      s     LKH'--/ Q
E\\%%j1
  0:szz'<'<=054,/ 	
 &+K
#.z:Fj#**"7"78-:e#LHZ 1>%'PL$#Q& h..r,   r   r   save_importc                     	 |j                         D ])  \  }}t        | |d   |d   |      }|j                  ||<   + y# t        $ r}t	        d|       d}~ww xY w)ud   Рекурсивно создаёт FK-объекты и подставляет их в current_obj.r   r   )r   r   r   u7   Не удалось обработать FK связь N)r$   process_any_table_fieldsrx   	ExceptionrI   )
import_objr   r   r   r|   inforesultes           r*   _process_fk_relationsr      s|    
\ , 2 2 4 	1J-7m>'	F '-jjK
#	1  \VWXVYZ[[\s   <? 	AAAr   c           	         |j                         D ]  \  }}|j                  |g        |d   }|d   }t        |      \  }}	|3t        j                  d|	      }
|j                  d      }|
D ]  }|j                         }|st        | |||i|rt        j                  nt        j                  |      }|j                  %| j                  d| d| d	d
|j                         ||   j                  |j                           y)u   
    Обрабатывает M2M-поля.

    Приоритет поиска: ext_id -> code -> name -> email -> login.
    Берётся первое непустое поле; значения разделяются по ',' или ';'.
    r   r   Nz[,;]cf_)r   r   moder   u&   Не найдено значение 'u   ' поля ''zERR-0135)obj_type)r$   
setdefault_pick_m2m_lookuprE   rC   
startswithrQ   r   rb   rj   rg   rx   	log_error
class_nameappend)r   r   r   r   r|   r   r   fields_datalookup_field	raw_valuevaluesdont_createvalr   s                 r*   _process_m2m_relationsr     s    %NN, 7
Dz2.W8n"2;"?i'9- ++E2 	7C))+C-#(#.-8Z))j>Y>Y'F zz!$$<SEj\YZ[*55 % 
 
#**6::6%	77r,   r   c                 N    t         D ]  }| j                  |d      }|s||fc S  y)un   Возвращает (field_name, value) первого непустого поля по приоритету. )NN)M2M_LOOKUP_FIELDSr;   )r   fnamer   s      r*   r   r   5  s3    " ooeR(#: r,   
filter_objc                 D   |r||dfS d|d<   |j                  dg       D cg c]  }|j                  j                   }}d|v r
d|d<   d|d<   d|v rFd	|vrBt        j                  j                  dd
|d   gdg      }|r||t        |d      fS |d   |d	<   ||dfS c c}w )u|   
    Спец. логика для CmfPerson.
    Возвращает (current_obj, filter_obj, early_result_or_None).
    NT
user_localrg_member_ofServiceDeskClientFemail_if_self_changesrt   ru   ILIKEz**filterr   rx   ry   )r;   rs   rR   modelsrm   rw   )r   r   r   pgrg_codesexisteds         r*   _apply_person_logicr   B  s     J,, $K(3(KL"LHLh&$)L!/4+,+'"<""&&Wk'&:;6 ' 
 
LWU,SSS*73G
D(( Ms   B_filter_objc                 b   g }|j                  d      r|j                  dd|d   g       |j                  d      r|j                  dd|d   g       |j                  d      r |j                  ddd|d   gdd|d   gg       |j                  d      r|j                  dd|d   g       ||dfS )ui   Спец. логика для CmfStatus — строит фильтр по status_type + workflow + name.r'   ==workflowrr   ORr   N)r;   r   _import_objr   r   
new_filters       r*   _apply_status_logicr   _  s     J}%=$M0JKLz":t[-DEFx 44X1F G-Y]_jks_tIuvwv64V)<=>
D((r,   c                     dd|d   gdd|d   gddt         j                  j                  |d   d      gdd|d   gg}||dfS )	u]   Спец. логика для CmfComment — фильтр по parent + author + date + text.rn   r   
cmf_authorcmf_created_atT)dayfirsttextN)dateutilparserparser   s       r*   _apply_comment_logicr   o  sq    
 
4X./	t[67OO!!+.>"?$!O	

 
{6*+	J 
D((r,   c                 p    t         j                  j                  |      }|s||d fS ||t        |d      fS )N)r   Fr   )r   CmfTestcaseFolderr;   rw   )r   r   r   r   s       r*   _apply_testcase_folder_logicr     sA     &&**+*>GK--\ge%LLLr,   c                     t         j                  t        t         j                  t        t         j
                  t        t         j                  t        i}|j                  |      }|||dfS  || ||      S )uf   Диспетчер model-specific логики. Возвращает early result если нужен.N)
r   rm   r   	CmfStatusr   
CmfCommentr   r   r   r;   )r   r   r   r   _MODEL_HANDLERShandlers         r*   _apply_model_specific_logicr     sn     	--/  ">	-O !!%(GJ,,:{J77r,   c           
         |r|S g }t         D ]P  }|j                  |d      }|s|dk(  r|j                  d|d|gdd|gdd|gg       n|j                  |d|g        n |s|j                         D ]  \  }}t	        |t
        j                  j                        }t        t        | |t        d            t
        j                  j                        }	|se|s|	sj|j                  | ddt        |j                        g        |rJ|j                  d	      r9| t        j                  t        j                   fv r|j                  d	d
|d	   g       |S )u'  
    Строит фильтр для поиска существующего объекта.

    Приоритет: ext_id (с OR по code) -> code -> name -> email -> login.
    Если ни одно уникальное поле не задано — фильтр по FK-полям.
    r   rr   r   r   rs   r   N_idrn   =)UNIQUE_LOOKUP_FIELDSr;   r   r$   r   r   r   	CmfEntityr   getattrtyper   r   rP   idCmfComponentCmfList)
r   r   r   _filterr|   rR   r   r   	is_entityis_rel_fields
             r*   _build_lookup_filterr     s\    G + 


B/!NN
D%0642G&RVX]I^_ NNJe45
 %++- 	CJE3"3

(<(<=I%ud4j13::3H3HL 	\5'tS[AB	C ;??8,; 2 	#{8'<=>Nr,   r   c                 h    |syt        |j                               dgz   }| j                  ||      S )uC   Ищет существующий объект по фильтру.Nr   r   )r   keysr;   )r   r   r   r   s       r*   _find_existingr     s5    +""$%-F99GF933r,   c                 n    i }|j                  d      r|d   |d<    | d||j                  d      dd|S )u:   Создаёт новый экземпляр модели.rn   r   T)
cmf_importr   import_originalrk   )r;   )r   r   r   kwargss       r*   _create_new_instancer     sP    Fx &x0x __V$ 	 r,   existing_objr   c                 x   |du }|r/|t         j                  t         j                  fv rt        dd      S |xs t	        | ||      }|j                         D ]  \  }}		 t        |||	        |t         j                  k(  rB|s@|j                  r4t	        | ||      }|j                         D ]  \  }}	t        |||	        d}|j                  rK|j                  s|s=|j                  r| j                  dk(  r|j                          |j                  |       t        ||      S #  t        d| d|	       xY w)ub   Создаёт или обновляет объект в зависимости от режима.NTr   u8   Не удалось присвоить значение r   rl   )r   )rb   rj   ri   rw   r   r$   setattrrI   rh   
is_changedr   ry   r   save)
r   r   r   r   r   r   ry   rx   r   r   s
             r*   _persist_objectr     s>    T!F $://1G1GHHT22

N.uj+NC!'') k
s	kC$k z%%%f"5*kB%++- 	%JE3C$	%
~~3..k::%**l:HHJ[)C//!	k #[\a[bbcdgch!ijjs   D&&D9Tc                 ,   t        ||      \  }}}t        | |||       t        | |||       t        | |||      \  }}}	|	|	S t	        |||      }
t        |||
      }|'|t        j                  k(  rd|vrd|
 }t        |      t        || ||||      S )u  
    Создание/обновление объектов на основании моделей при импорте.

    :param import_obj: Объект импорта (CmfImport / CmfProjectImport), имеющий log_error
    :param model: Модель, по которой создаётся объект
    :param obj_fields: Параметры объекта
    :param filter_obj: Фильтр для поиска существующего объекта
    :param mode: Режим импорта (создать, обновить, и т.д.)
    :param save_import: Сохранять ли связь с импортом
    :return: ImportResult(obj, is_new)
    ru   u0   Не нашли пользователя filter=)
r   r   r   r   r   r   r   rm   rI   r   )r   r   r   r   r   r   r   r   r   early_resultr   r   msgs                r*   r   r     s    ( +8z*J'L+x *lKM :xkJ -HE;
-)K\  #5+zBG!%g>L 	V%%%;&@	JS!! z;dK r,   )4rf   dataclassesr   enumr   r   rE   dateutil.parserr   loggingtempfileostypingr   r   r   r	   r
   r   cmf.includerP   r+   rD   r6   r>   rN   rW   r`   rb   rq   rz   r   r   rw   r   r   r   r{   r   r   r   r   r   r   r   r   r   r   r   r   rg   r   rk   r,   r*   <module>r     st   "  	    	 = = )3 )3 )X  	<m m0,# # (  ) tCH~  A  D    s 4 "/T /eD$4D.E /J\\ \ 	\
 
\(*7*7 *7 	*7
 
*7Z$ 5#1M+N )!)/7~)
4$,!778):)")19$)
4$,!778) )")19$)
4$,!778)"M"M19$M
4$,!778M8$(86>tn8
4$,!7788**T *x~ *RV *b4t 4d 4x} 4
 
# 
$0 $0 3-	$0
 $0 $0 $0^ "&!223 3 	3
 3 3 3r,   