
    i߇                         d Z ddlmZ ddl ddl ddlZddlZddl ddl	Z	ddl
ZddZd Z G d d      Z ed	d
d      	 	 	 	 	 dd       Zd Zd Zd Zd Zd Zy)u  
Модуль экспорта данных в различные форматы файлов (CSV, XML, XLSX).

Основная задача - выгрузка данных из моделей CMF в файлы с поддержкой различных форматов.
    )defaultdict)*Nc                    ddl m}m} t        j                  j	                         }	|	j                  d      }
dt        j                  j                   d|
 d| }t        j                  t        j                  |      }|j                         5  |j                          ddd        |t        | |j                  |||||d|	       |j                  S # 1 sw Y   7xY w)
u  
    Публичная функция для запуска отложенной задачи экспорта данных.
    
    Создает attachment для результата и запускает фоновую задачу export2file_task.
    
    Args:
        class_name: Имя класса модели CMF для экспорта
        field_names: Список полей для экспорта (если None - все видимые поля)
        bql: BQL фильтр для выборки данных
        format_file: Формат файла ('csv', 'xml', 'xlsx')
        include_archived: Включать ли архивные записи
        order_by: Поле для сортировки
        **kwargs: Дополнительные параметры (roadmap_ordered_ids, roadmap_level_of и т.д.)
        
    Returns:
        URL созданного attachment с результатом
    r   )schedule_deferred_jobcmfutilz%Y%m%d%H%M%Szexport..)parentnameN)
class_nameres_attachment_idfield_namesbqlformat_fileinclude_archivedorder_by)kwargs)cmf.includer   r   datetimenowstrftimegcurrent_useridmodelsCmfAttachmentdisable_aclsaveexport2file_taskurl)r   r   r   r   r   r   r   r   r   r   formatted_timeexport_filename
attachments                ./cmf/util/cmf_export.pyexport2filer$      s    $ ; 




!C \\.1N   1 12!N3C1[MRO%%Q^^/%RJ				 **ISCN;>CNHX@H4> 7=4> ? >> s   CC c                     | syt         j                  j                  |       }|j                         j	                         S )u  
    Удаляет HTML теги из строки и возвращает чистый текст.
    
    Использует lxml для быстрого парсинга HTML. Если парсинг не удался,
    возвращает исходную строку как есть.
    
    Args:
        html_content: Строка с HTML разметкой
        
    Returns:
        Строка без HTML тегов
     )lxmlhtml
fromstringtext_contentstrip)html_contentdocs     r#   _strip_htmlr.   ?   s6     
))

|
,C##%%    c                   H    e Zd ZdZd ZdefdZd ZddZd Z	d	 Z
d
efdZy)ExportDataManageruc  
    Менеджер для управления процессом экспорта данных.
    
    Инкапсулирует логику работы с данными: пагинация, проверка прав доступа,
    конвертация значений полей, получение метаданных полей.
    c                 d    || _         || _        || _        || _        || _        ddlm} || _        y)u  
        Инициализация менеджера экспорта.
        
        Args:
            cls: Класс модели CMF для экспорта
            bql: BQL фильтр для выборки данных
            include_archived: Включать ли архивные записи
            order_by: Поле для сортировки
            forced_captions: Словарь принудительных заголовков полей
        r   r   N)clsr   r   r   forced_captionsr   r   )selfr4   r   r   r   r5   r   s          r#   __init__zExportDataManager.__init__Z   s3      0 .'r/   returnc                 n   	 | j                   j                  |j                        }|j                  }t	        |t
        j                  j                        xr |j                  }t	        |t
        j                  j                        xr |j                  }t	        |t
        j                  j                        xr |j                  }t	        |t
        j                  j                        xr |j                  }t        j                  j                  ||j                  ||j                  ||d|d	      S )uC  
        Проверяет права доступа к объекту для чтения.
        
        Args:
            obj: Объект модели CMF для проверки
            
        Returns:
            True если доступ разрешен, False в противном случае
        readF)	initial_acl_keyobject_modelobject_owner_id	object_idobject_parent_idobject_dictaccess_levelperm_security_level_allowed_idsraise_error)r   get_model_by_namer   __dict__
issubclasscmfr   	CmfEntityperm_effective_acl_idCmfModelcmf_owner_id	parent_id%perm_security_level_allowed_ids_cacheCmfAccessListcheck_accessr   )r6   objmodelobj_dictr;   obj_owner_idobj_parent_idrM   s           r#   check_access_objz"ExportDataManager.check_access_objm   s    	 ..s~~><<$UCJJ,@,@A_cF_F_!%)<)<=R#BRBR"5#***=*=>P3==0:5#**BVBV0W  1F\_  ]F  ]F-##00+#..Zfff}(,Q_d	 1 
 	
r/   c              #     K   d}d}d|vrdg|z   }g d}	 | j                   j                  | j                  |||z   g||z   | j                  | j                        }|sy||z  }|D ]T  }| j                  |      st        | j                   d      r| j                   j                  |      }n|g}|D ]  }|  V w)uP  
        Генератор для постраничной загрузки данных с проверкой прав доступа.
        
        Загружает данные пакетами по 50000 записей, фильтрует по правам доступа
        и возвращает только разрешённые записи.
        
        Args:
            fields: Список полей для экспорта. Если '--' отсутствует, добавляется в начало.
            
        Yields:
            Записи, к которым пользователь имеет доступ на чтение.
            
        Note:
            Для проверки доступа автоматически подключаются служебные поля:
            - cmf_owner_id, cmf_author_id — владелец и автор
            - access_author, access_responsible — права автора и ответственного
            - perm_security_level_id — уровень безопасности
            - responsible_id, spectators, executors — исполнители и наблюдатели
            - project_id, parent_id — иерархия
            - perm_effective_acl_id, perm_security_level_allowed_ids_cache — кэш ACL
        r   iP  --)rK   access_authorcmf_author_idperm_security_level_idaccess_responsibleresponsible_id
spectators	executors
project_idrL   rI   rM   )filterslicefieldsr   r   export_hookN)r4   slistr   r   r   rU   hasattrrc   )	r6   rb   startstepsecurity_fieldsdatarowrowssub_rows	            r#   paginate_datazExportDataManager.paginate_data   s     , vVf_F

 88>>$)54<#8$*_$<.2.C.C&*mm	 " 5D
 TME ",,S1488]388//4D5D# "G!M"" s   B<B>Nc                    |yt        |d      rt        |j                        S t        |d      rt        |j                        S t	        |t
              r.dj                  |D cg c]  }| j                  |       c}      S |rZt        |t        j                  j                  t        j                  j                  f      r|j                  j                  ||      S |rt        |      S dS c c}w )u"  
        Конвертирует значение поля в строку для экспорта.
        
        Обрабатывает различные типы данных: None, объекты с атрибутами name/id,
        списки, поля CmfChoiceInt и CmfChoice.
        
        Args:
            val: Значение поля
            field_obj: Объект поля (опционально)
            
        Returns:
            Строковое представление значения
        r&   r
   r   ,)re   strr
   r   
isinstancelistjoinconvert_valrF   rG   rb   CmfChoiceInt	CmfChoicechoicesget)r6   val	field_objrj   s       r#   rt   zExportDataManager.convert_val   s     ;S&!sxx= S$svv;T"88cBsT--c2BCC:i#**2I2I3::K_K_1`a$$((c22"3s8**	 Cs   %C/c                     t        ||      rt        ||      S |j                  d      D ]  }t        ||      st        ||      c S  y)u  
        Получает поле объекта. Работает с вложенными полями через точку.
        
        Например: get_included_attr(doc, 'person.second_name')
        
        Args:
            obj: Объект модели
            field_str: Имя поля (может содержать точку для вложенных полей)
            
        Returns:
            Значение поля или None
        r   N)re   getattrsplit)r6   rP   	field_strfields       r#   get_included_attrz#ExportDataManager.get_included_attr   sJ     3	"3	**__S) 	+EsE"sE**	+r/   c                    |j                  d      }|}t        |      D ]  \  }}t        ||d      }|s't        |d      r|j                  j                  |      }|t        |      dz
  k(  s|s|c S t        |d      r)t        t              j                  |j                        }t        |d      r8|j                  r,t        t              j                  |j                  d         } y y)un  
        Рекурсивно получает объект поля, учитывая вложенность через точку.
        
        Args:
            class_obj: Класс модели
            field_name: Имя поля с учетом вложенности
            
        Returns:
            Объект поля или None
        r   Nrb      rQ   r   r   )
r}   	enumerater|   re   rb   rx   lenvarsr   rQ   )r6   	class_obj
field_namepartscurrent_objipartrz   s           r#   get_field_objzExportDataManager.get_field_obj   s       % ' 	GAtT48Ih!?'..2248	CJN")  y'*"6l..y?H-)2B2B"6l..y/?/?/BC	 r/   fields_namec                 T      fdi }|D ]  }  j                   |      ||<    |S )u  
        Получает заголовки (caption) для списка полей.
        
        Учитывает forced_captions, вложенные поля и связанные сущности.
        
        Args:
            fields_name: Список имен полей
            
        Returns:
            Словарь {имя_поля: заголовок}
        c           
         |
j                   v r
j                   |   S |j                  d      }| j                  j                  |d         }ddi}|sY| j                  |j                         v r=t        t              || j                        }|j                  j                  |d         }|}t        t        t                    }t        j                  j                  |d<   |r|j                  }t        |      dkD  rft        |d      r|j                  r|j                  d   }nt        |d      r|j                  }n|S | d 	||   dj                  |dd               }|S )	Nr   r   CmfTestplanTestcaseCmfTestcaserH   r   r   rQ   )r5   r}   rb   rx   r   keysr   r   copyrG   rH   captionr   re   rQ   rs   )r   r   pural_namesr   linked_entitylinked_class_objres
models_cls
model_nameget_captionr6   s            r#   r   z3ExportDataManager.get_captions.<locals>.get_caption  sQ   T111++J77$**3/K$$((Q8E%}M Y11]5G5G5II#'<i>R>R0S#T (//33KNCCd6l+J&)jj&:&:J{#mm{#a'uh/ELL%*\\!_
 0%*[[
"
 E;z*/EsxxP[\]\^P_G`#a"bcCJr/   )r4   )r6   r   r   r   r   s   `   @r#   get_captionszExportDataManager.get_captions  s9    	6 % 	@J)$((J?C
O	@
r/   )N)__name__
__module____qualname____doc__r7   boolrU   rm   rt   r   r   rr   r    r/   r#   r1   r1   R   s:    &
t 
B2"h+6+&<* *r/   r1   u'   Экспорт данных в файл   T)descriptionpriorityshow_bg_progressbarc                 r   | dk(  rd} ddddd}t        t              |    t        j                  j                  |      }	t	        ||||      s?j
                  j                         D 
cg c]  }
|
j                  s|
j                   c}
t               }r|j                  d	       t               D ]  }r|d
k(  rj                  g d       nj|dk(  rd}d|d<   n]j
                  j                  |      rBt        j
                  j                  |      t        j
                  j                        r|dz  }|j                  |        |j                        D 
ci c]  }
|
j!                  |
       c}
fd}fd}fd}fd}ddlm} t'        j(                         5 }	 | d| }|dk(  r	 ||       n*|dk(  r	 ||       n|dk(  r	 ||       nt+        d|       t-        |d      5 }|j/                         5  |	j1                  |dd       ddd       ddd       ddd       yc c}
w c c}
w # 1 sw Y   $xY w# 1 sw Y   (xY w# t2        $ r#}t4        j7                  d| d | d!"        d}~ww xY w# 1 sw Y   yxY w)#zN
    https://bcrm.carbonsoft.ru/project/Document/DOC-007693#spec-007668-b
    
CmfRoadmapCmfTasku   Индикаторыu   №u   Предшественникиu   Последлователи)custom_column_indicatorscustom_column_sequence_numbercustom_column_predecessorscustom_column_followers)r   r   r   )z op_gantt_task.actual_finish_datezop_gantt_task.sched_finish_datez"op_gantt_task.constrain_start_typez"op_gantt_task.constrain_start_datez#op_gantt_task.constrain_finish_typez#op_gantt_task.constrain_finish_datetimetracker_historyzop_gantt_task.actual_workuG   Журнал работ.Фактические трудозатратыz.namec                    ddl }t        | dd      5 }|j                  |dd|j                        }g }t	        j                              D ]  \  }}g }D ]  }|dk(  rT|j                  j                  |             |j                  d	      r#|j                  j                  |       d
       j                  ||      }	j                  |      }
j                  |	|
      }|j                  |       |j                  d	      s|j                  t        |              |dk(  r|j                  |       |j                  |        	 ddd       y# 1 sw Y   yxY w)u   
        Записывает данные в файл формата CSV.
        
        Args:
            file_path: Путь к файлу для записи
        r   Nzw+r&   )newline;")	delimiter	quotecharquotingtext    без html)csvopenwriterQUOTE_MINIMALr   rm   appendrx   endswithr   rt   r.   writerow)	file_pathr   csvfiler   csv_headr   rj   csv_rowr   field_valuerz   val_strcaptionsdata_managerr   field_objects_caches               r#   
_write_csvz$export2file_task.<locals>._write_csvp  sH    	)T2. 	)'ZZ3#sO`O`ZaFH#L$>$>{$KL )3( =EAv U(;< >>&1$OOx||E/B.C<,PQ"."@"@e"LK 3 7 7 >I*66{INGNN7+ ~~f-{7';<=  6OOH-())	) 	) 	)s   C:EAEE(c                 	   ddl m} ddlm} |j	                  d      }|j                  dd       |j	                  d      }|j                  |       |j	                  d      }d	|_        |j                  |       |j	                  d
      }dt               v rt        j                  nd|_        |j                  |       |j	                  d      }d|_        |j                  |       |j	                  d      }d|_        |j                  |       |j	                  d      }	|	j                  dd       |j                  |	       |j	                  d      }
|j                  |
       d}t        j                              D ]  \  }}|j	                  d      }t               }|j                  |       D ]  }|j                  d      }j                  j!                  |d         }|d   |vr1|j	                  |d         ||d   <   |j                  ||d             |j!                  |d         }t#        ||d   d       }|rt%        |t&        j                  j(                        r|st+        t,              |j.                     j                  D ]K  }|dk(  r|j0                  |_        t3        ||      s'|j                  |t5        t#        ||                   M |j                  d|j6                         J|rt%        |t&        j                  j8                  t&        j                  j:                  f      r|s|j                  d|j6                         |D ]Z  }|j	                  d      }|j                  dt5        |j<                               |j0                  |_        |j                  |       \ |rgt%        |t&        j                  j>                        rC|5|j@                  j!                  |d      |_        |j                  d|j6                         tt5        jC                  ||            |_        |j                  dj!                  ||               |	j                  dt5        |             |	j                  dt5        |              ||       jE                  |jG                  |             y )Nr   ElementTreePathrssversion0.92channeltitleEvaTeamlinkrequestr&   r   +   XML представление данныхlanguageru-rutaskrf   0
build_infoitemr   r
   r   valuer   endtotal$	xml.etreer   pathlibr   Elementsetr   r   globalsr   r   r   rm   dictr}   rb   rx   r|   rF   rG   CmfRelationBaser   r   r   r
   re   rp   r   
CmfM2MBaseCmfBackrefBaser   ru   rw   r   write_bytestostringr   ETr   r   r   r   r   r   r   r   r   r   rj   r   elementsr   r   r   
field_infor   keyvr   r   r4   r   r   s                          r#   
_write_xmlz$export2file_task.<locals>._write_xml  s   / jj	6"**Y'

7

7#
uzz&!#,	#9GKKr	tjj/H{#::j)x zz&!#tZZ-
z" : :; GH %	TFAs::f%DvHNN4 ) !T
(..s3

{1~6"1~1/1zz+a./IH[^,KKQ 89%\\+a.9
%c;q>4@Zszz/I/IJ"#'<0F0F#G#N#N TC"f}2=2B2B
 (&{C8 *sCS8Q4R ST #y%--@z%#**2G2GIbIb1cd""y%--@!, 5A$&JJw$7E!IIdCI6)*EJ&--e4	5
 z%1H1HI"* &+mm&7&7R&HJONN9emm<&),*H*Hj*Y&ZJONN9hll:z.RSC!T	%	TN 	A#a&!Y##BKK$45r/   c                 	   ddl m} ddlm} |j	                  d      }|j                  dd       |j	                  d      }|j                  |       |j	                  d      }d	|_        |j                  |       |j	                  d
      }dt               v rt        j                  nd|_        |j                  |       |j	                  d      }d|_        |j                  |       |j	                  d      }d|_        |j                  |       |j	                  d      }	|	j                  dd       |j                  |	       |j	                  d      }
|j                  |
       d}t        j                              D ]  \  }}|j	                  d      }t               }|j                  |       D ]  }|j                  d      }j                  j!                  |d         }|d   |vr1|j	                  |d         ||d   <   |j                  ||d             |j!                  |d         }t#        ||d   d      }|rt%        |t&        j                  j(                        r|st+        t,              |j.                     j                  D ]K  }|dk(  r|j0                  |_        t3        ||      s'|j                  |t5        t#        ||                   M |j                  d|j6                         J|rt%        |t&        j                  j8                  t&        j                  j:                  f      r|s|j                  d|j6                         |D ]Z  }|j	                  d      }|j                  dt5        |j<                               |j0                  |_        |j                  |       \ |rgt%        |t&        j                  j>                        rC|5|j@                  j!                  |d      |_        |j                  d|j6                         tt5        jC                  ||            |_        |j                  dj!                  ||               |	j                  dt5        |             |	j                  dt5        |              ||       jE                  |jG                  |             y)u   
        Записывает данные в файл формата XML (RSS 0.92).
        
        Args:
            file_path: Путь к файлу для записи
        r   r   r   r   r   r   r   r   r   r   r   r&   r   r   r   r   r   rf   r   r   r   r   Nr
   r   r   r   r   r   r   r   s                          r#   r   z$export2file_task.<locals>._write_xml  s    	0 jj	6"**Y'

7

7#
uzz&!#,	#9GKKr	tjj/H{#::j)x zz&!#tZZ-
z" : :; GH %	TFAs::f%DvHNN4 ) !T
(..s3

{1~6"1~1/1zz+a./IH[^,KKQ 89%\\+a.9
%c;q>4@Zszz/I/IJ"#'<0F0F#G#N#N TC"f}2=2B2B
 (&{C8 *sCS8Q4R ST #y%--@z%#**2G2GIbIb1cd""y%--@!, 5A$&JJw$7E!IIdCI6)*EJ&--e4	5
 z%1H1HI"* &+mm&7&7R&HJONN9emm<&),*H*Hj*Y&ZJONN9hll:z.RSC!T	%	TN 	A#a&!Y##BKK$45r/   c                    ddl m} |j                         }|j                  d_        g dfd	}rt               t               dv sdv rt               \  j                  dg       }j                  d	t                     j                  d
t                     j                  z         D ci c]  }t        |j                        | }}d}t        |d      D ]*  \  }}	|j                  |	d      }
|
s ||
||	|       |dz  }, n+t        j                              D ]  \  }}
 ||
|        |j                  |        yc c}w )u  
        Записывает данные в файл формата XLSX.
        
        Поддерживает группировку строк (outlineLevel) для roadmap.
        
        Args:
            file_path: Путь к файлу для записи
        r   )workbooku   ВыгрузкаNc           
         g }D ]  }|dk(  rGj                  j                  |             |dv r#j                  j                  |       d       r|dk(  r|j                  |dz          lr`|dk(  r[j                  |g       }|D cg c]  }t        j                  |d              }}|j                  dj                  |             Ήra|dk(  r\j                  |g       }	|	D 
cg c]  }
t        j                  |
d              }}
|j                  dj                  |             1r!|d	k(  r|j                  t	        |              Tj                  | |      }j                  |      }j                  ||      }|j                  |       |dv s|j                  t        |              |dk(  rj                         j                  |       r|r|rj                  t        ||f      d      }j                  }j                  |   }t        |d
      |_        |dkD  |_        j                  |d      }|j                  d|dz  z   |j                   |_        y y y y y c c}w c c}
w )Nr   )r   result_textr   r   r   r   z; r   r      )rj   column    )r   rx   rp   rs   _indicator_textr   rt   r.   max_rowrow_dimensionsminoutlineLevelhiddencellr   )row_objrow_idxtidseqr   r   predecessorsp_tid sequence_numbers_of_predecessors	followersf_tidsequence_numbers_of_followersr   rz   r   depthxl_rowrd
first_cellr   r   r   r   r   followers_offrom_roadmappredecessors_ofroadmap_level_ofroadmap_sequence_map
sheet_xlsxs                      r#   	write_rowz8export2file_task.<locals>._write_xlsx.<locals>.write_row?  sw   G$ =a<OOHLL$78 77 8<<+>*?|(LME-L$LNN7Q;/!e/K&K#2#6#6sB#?Lp|7}gl<P<T<TUZ\`<a8b7}47}NN499-M#NO!e/H&H , 0 0b 9Imv4wdiS9M9Q9QRWY]9^5_4w14wNN499-J#KL!e/I&INN?7#;<"."@"@%"PK 3 7 7 >I*66{INGNN7+ 77{7';<1=4 !|!!(+g&(,,S#s_a@#++..v6"%eQ-!AI	'___B
##/*-*;)<Z=M=M<N'OJ$ 0 ),|) 8~ 5xs   "J1"Jr   r   roadmap_ordered_idsr  r  r   )rf   )NN)openpyxlr   Workbookactiver   r   $_prepare_predecessors_followers_mapsrx   rm   rp   r   r   r   )r   r   	book_xlsxr  r  rP   	id_to_objr   r  r  rj   r   r  r  r  r  r  additional_fieldsr   r   r   r   r  r   s              @@@@@@r#   _write_xlsxz%export2file_task.<locals>._write_xlsx/  sh    	&%%'	%%
-
(	P (	PT 6L"fO+{:>W[f>f0T0V-o"(**-BB"G%zz*<dfE#)::.Ddf#M 5A5O5OP[^oPo5pqcSVVc)qIqA%&9C SmmC.#q#s+Q $L$>$>{$KL "3#q!" 	y! rs   
E#r   r3   z/export.r   xmlxlsxu0   Формат не поддерживается: rbF)backupmake_previewNzError during export to z: ERROR)level)r   r   r   rx   r1   rb   valuesvisibler   rr   r   extendrF   rG   
CmfRelBaser   r   r   r   tempfileTemporaryDirectory
ValueErrorr   r   upload_stream_file	Exceptionr   debug)r   r   r   r   r   r   r   r   r5   r"   r   
new_fieldsr   r   r   r   r   tmpdirr   fer  r   r4   r   r   r  s     `    `             @@@@@@r#   r   r   :  s    -L
$:).&F#A	O v,z
"C%%))->)?J$S#/??[L58ZZ5F5F5HZEEMMu''Z J9:! 
&
J*DD$$ &t u 004J <EO78ZZ^^J'Jszz~~j7QSVS]S]ShSh,i'!J*%
& K((5H WbbU5,"<"<S%"HHb)BJ6XP6dP" P"b $		$	$	& &	!((;-8Ie#9%%9%&I& #ST_S`!abbi& W!((* W11!EPU1VWW S	 [, cD	W WW W
  	GG-k]"QC@GP	% sm   8I
I6I!J-AI>I2.I&I2I>&I/+I22I;	7I>>	J*J%%J**J--J6c                  B   t        t              } t        t              }g d}g d}t        j                  j	                  ||      D ]R  }| |j
                     j                  |j                         ||j                     j                  |j
                         T | |fS )u  
    Подготавливает карты связей предшественников и последователей для roadmap.
    
    Загружает все связи типа 'system.finish:start' и строит словари:
    - followers_of: {id_задачи: [id_последователей]}
    - predecessors_of: {id_задачи: [id_предшественников]}
    
    Returns:
        Кортеж (followers_of, predecessors_of)
    )rW   out_link_id
in_link_id)zrelation_type.codez==zsystem.finish:start)rb   r`   )r   rr   r   CmfRelationOptionrd   r7  r   r8  )r  r  _fields_filterrels        r#   r  r    s     t$L!$'O/G?G''--WW-M @S__%,,S^^<'..s?@ ((r/   c                 2    dddd}|j                  | |       S )u@  
    Получить текстовое название для типа ограничения начала задачи.
    
    Args:
        code: Код типа ограничения ('0-const', '3-after', '4-before')
        
    Returns:
        Текстовое название ограничения
    u   Фиксированная   Не раньше   Не позже0-constz3-afterz4-beforerx   )codestart_restriction_names     r#   _get_start_restriction_lablerE    s*     4*)
 "%%dD11r/   c                 2    dddd}|j                  | |       S )uF  
    Получить текстовое название для типа ограничения окончания задачи.
    
    Args:
        code: Код типа ограничения ('0-const', '1-after', '2-before')
        
    Returns:
        Текстовое название ограничения
    u   Фиксированныйr>  r?  rA  z1-afterz2-beforerB  )rC  finish_restriction_lables     r#   _get_finish_restriction_lablerI    s*     4*) 
 $''d33r/   c                    t        | t        j                        r| j                  d      S t        | t        j                        rDt        j                  | j                  | j
                  | j                        j                  d      S y)u   
    Форматирует дату в строку dd.mm.yyyy (как на фронтенде).
    
    Args:
        d: Объект datetime или date
        
    Returns:
        Отформатированная строка даты
    z%d.%m.%Yr&   )rq   r   r   dateyearmonthday)ds    r#   _format_daterP    s`     !X&&'zz*%%!X]]#  !%%8AA*MMr/   c                 V   t        | dd      }|syt        |dd      }|rdt        |       dS g }t        |dd      }|dv rCt        |      }d	| d
}t        |dd      }|r|dt        |       dz  }|j                  |       t        |dd      }|dv rCt	        |      }d	| d}t        |dd      }	|	r|dt        |	       dz  }|j                  |       t        | dd      }
t        |dd      }|r%|
r#||
kD  r|j                  dt        |
       d       dj                  |      S )u  
    Формирует текстовое описание индикатора состояния задачи roadmap.
    
    Включает информацию о завершении задачи, ограничениях по датам начала и окончания,
    а также предупреждения о нарушении дедлайна.
    
    Args:
        instance: Объект задачи (CmfTask)
        
    Returns:
        Текстовое описание индикатора
    op_gantt_taskNr&   actual_finish_dateu   Была завершена "r   constrain_start_typer@  u/   Установлено ограничение "u    " для "Дата начала"constrain_start_dateu    на "constrain_finish_typerG  u&   " для "Дата окончания"constrain_finish_datedeadlinesched_finish_dateuS   Указана дата окончания позже крайнего срока "
)r|   rP  rE  r   rI  rs   )instance
gantt_taskactual_finishlines	cst_valuelabellinecsd	cft_valuecfdrX  sched_finishs               r#   r   r     s    ?D9J J(<dCM.|M/J.K1MME 
$:DAI66,Y7@Gghj"8$?gl3/022DT 
$;TBI55-i8@Gmnj"94@gl3/022DT xT2H:':DAL\H%<jkw  yA  lB  kC  CD  E  	F99Ur/   )NNNr   FN)NNr   FN)r   collectionsr   r   
cmf.configr   
cmf.fieldsrG   r   r,  	lxml.htmlr'   r$   r.   r1   cmf_deferred_jobr   r  rE  rI  rP  r   r   r/   r#   <module>rk     s    $       )Z&&f fP GRSimn "&!&&+"Z oZ@)(2$4$"3r/   