
    rj>                    .   d dl Zd dlZd dlZd dlmZ d dlmZmZ d dl	m
Z
mZmZmZmZmZ d dlZd dlZd dl d dlmZ d dlmZmZ dd	d
ddddddddddZej                  Zej4                  Zej                  ZdZdZd ZdZ  G d dejB                        Z!y)    N)	lru_cache)deque
namedtuple)IteratorListNoReturnTupleUnionOptional)*)cmf_calendar)MOrelativedeltau   янвu   февu   марu   апрu   маяu   июнu   июлu   авгu   сенu   октu   нояu   дек)                        	   
         r      (   c                       e Zd Zej                  j
                  dz   Zej                  j                  ddgz   Zededede	e   fd       Z
e	 	 dIded	ed
ededef
d       Ze	 	 dJdededededee   f
d       Ze	 	 dKdededededee   dee   fd       Ze	 	 	 dLdedededed	ed
ededee   fd       Ze	 	 	 dMdedededed	ed
ededee   fd       Ze	 	 dNdededeeef   fd       ZedNdededefd       Zedddeeee   f   fd       Zd Zedd dedefd        Ze	 	 dOdd deded"edef
d#       Z ed$d%      Zede e!d e"jF                  jH                  f   dedefd&       Z%ed'        Z&e e'd(      d)               Z(i Z)i Z*e e+d*+      dPd,e!ded-e,e!   defd.              Z-e	 dPdd d/e e!eeef   defd0       Z.dQd1ed2edefd3Z/d4ed5edefd6Z0e	 dRdd d4ed5edefd7       Z1e	 dSdd d4ed8edefd9       Z2ed:        Z3ed;        Z4ed<        Z5e e6d!d!d=d>?      d@               Z7dA Z8dB Z9dC Z:dD Z; fdEZ< fdFZ=dG Z> fdHZ? xZ@S )TCmfCalendar)DayDatarecalc_calendarload_holidays
date_startdate_endreturnc              #      K   t        t        || z
  j                        dz         D ]  }| t        j                  |      z     yw)u   
        Генератор диапазона дат

        Args:
            date_start (Date): начальная дата
            date_end (Date): конечная дата

        Yields:
            Iterator[Date]: дата
        r   N)rangeintdaysdatetime	timedelta)r#   r$   is      ./common/models/cmf_calendar.py_date_rangezCmfCalendar._date_range'   sG      sHz17781<= 	5Ax11!444	5s   AAdate	month_daypositionday_of_weekc                    |rHt        j                  | j                  | j                        d   }||k  r|}| j	                  |      }|S t        j
                         }|j                  | j                  | j                        }|D cg c]$  }||   j                  | j                  k(  s ||   & }	}|dk  r|	|   n|	d   }|S c c}w )u:  
        Вспомогательный метод для every_month и every_year
        Возвращает дату по указанному дню месяца или по позиции дня недели месяца

        Args:
            date (Date): дата
            month_day (int, optional): день месяца (1-31). Defaults to None.
            position (int, optional): позиция недели месяца. Defaults to None.
                                      (0-первая, 1-вторая, 2-третья, 3-четвертая, 4-последняя)
            day_of_week (int, optional): день недели. Defaults to None.
                                         (0-ПН, 1-ВТ, 2-СР, 3-ЧТ ,4-ПТ ,5-СБ, 6-ВС)

        Returns:
            Date: дата
        r   )dayr   )cl
monthrangeyearmonthreplaceCalendarmonthdatescalendar)
r/   r0   r1   r2   days_in_monthr4   calendarweeksweekday_of_weekss
             r-   _get_day_by_position_in_monthz)CmfCalendar._get_day_by_position_in_month6   s    $ MM$))TZZ@CMy()	,,9,-C 
 {{}H//		4::FE:?i$4CTCZCZ^b^h^hChD-iLi,4qL,x(l2>NC
 js   	!C+C
start_dateend_daterepeatsperiodc                     g }|d}| }|r3||dz  }n||kD  r	 |S |j                  |       |t        |      z  }|r3|S )u  
        Возвращает список дат для типа повторения "Ежедневно"

        Args:
            start_date (Date): начальная дата
            end_date (Date, optional): конечная дата. Defaults to None.
            repeats (int, optional): количество повторений. Defaults to None.
            period (int, optional): периодичность (каждый N день). Defaults to 1.

            Обязателен один из двух аргументов, либо end_date, либо repeats

        Returns:
            List[Date]: список дат
        Tr   r)   )appendr   )rC   rD   rE   rF   r)   current_dates         r-   	every_dayzCmfCalendar.every_dayU   sf    " G!1(
  KK%Mv66L      weekdaysc                     g }|d}| t        t        d            z   }|rS|D ]<  }|t        |      z   }|| k\  r"||dz  }n	||kD  rd} n|j                  |       |r< n |t        |      z  }|rS|S )u]  
        Возвращает список дат для типа повторения "Еженедельно"

        Args:
            start_date (Date): начальная дата
            end_date (Date, optional): конечная дата. Defaults to None.
            repeats (int, optional): количество повторений. Defaults to None.
            period (int, optional): периодичность (каждая N неделя). Defaults to 1.
            weekdays (List[int], optional): список дней недели. Defaults to None.
                                            (0-ПН, 1-ВТ, 2-СР, 3-ЧТ ,4-ПТ ,5-СБ, 6-ВС)

            Обязателен один из двух аргументов, либо end_date, либо repeats

        Returns:
            List[Date]: список дат
        Tr5   )weekdayr   F)r?   )r   r   rI   )	rC   rD   rE   rF   rM   r)   rJ   rO   r4   s	            r-   
every_weekzCmfCalendar.every_weekw   s    & G!M"R&$AA# "]7%CC*$'1x"'KK$ M77L   rL   c                    g }|d}| }|rt         j                  ||||      }	|	| k\  r!||dz  }n|	|kD  r	 |S |j                  |	       |j                  dz
  |z   }
|j                  |
dz  z   }|
dz  dz   }
|j                  ||
      }|r|S )u  
        Возвращает список дат для типа повторения "Ежемесячно"
        Расчитывает даты в двух режимах:
            1 - по указанному дню, если установлен параметр month_day
            2 - по позиции дня недели, если установлены параметры position и day_of_week

        Args:
            start_date (Date): начальная дата
            end_date (Date, optional): конечная дата. Defaults to None.
            repeats (int, optional): количество повторений. Defaults to None.
            period (int, optional): периодичность (каждый N месяц). Defaults to 1.
            month_day (int, optional): день месяца (1-31). Defaults to None.
            position (int, optional): позиция недели месяца. Defaults to None.
                                      (0-первая, 1-вторая, 2-третья, 3-четвертая, 4-последняя)
            day_of_week (int, optional): день недели. Defaults to None.
                                         (0-ПН, 1-ВТ, 2-СР, 3-ЧТ ,4-ПТ ,5-СБ, 6-ВС)

            Обязателен один из двух аргументов, либо end_date, либо repeats

        Returns:
            List[Date]: список дат
        Tr0   r1   r2   r   r   )r8   r9   )r   rB   rI   r9   r8   r:   )rC   rD   rE   rF   r0   r1   r2   r)   rJ   r4   r9   r8   s               r-   every_monthzCmfCalendar.every_month   s    4 G!;;LT]EM[f < hC j #qLG8^  C  &&*V3E$$u{2DBJNE'//T/GL! $ rL   r9   c                     g }|d}| j                  |d      }|rat        j                  ||||      }	|	| k\  r!||dz  }n|	|kD  r	 |S |j                  |	       |j                  |j                  dz         }|ra|S )u  
        Возвращает список дат для типа повторения "Ежегодно"
        Расчитывает даты в двух режимах:
            1 - по указанному дню, если установлены параметры month и month_day
            2 - по позиции дня недели месяца, если установлены параметры month, position и day_of_week

        Args:
            start_date (Date): начальная дата
            end_date (Date, optional): конечная дата. Defaults to None.
            repeats (int, optional): количество повторений. Defaults to None.
            month (int, optional): месяц (1-Янв, 2-Фев, ..., 12-Дек). Defaults to None.
            month_day (int, optional): день месяца (1-31). Defaults to None.
            position (int, optional): позиция недели месяца. Defaults to None.
                                      (0-первая, 1-вторая, 2-третья, 3-четвертая, 4-последняя)
            day_of_week (int, optional): день недели. Defaults to None.
                                         (0-ПН, 1-ВТ, 2-СР, 3-ЧТ ,4-ПТ ,5-СБ, 6-ВС)

            Обязателен один из двух аргументов, либо end_date, либо repeats

        Returns:
            List[Date]: _description_
        Tr   r9   r4   rR   )r8   )r:   r   rB   rI   r8   )
rC   rD   rE   r9   r0   r1   r2   r)   rJ   r4   s
             r-   
every_yearzCmfCalendar.every_year   s    4 G!))1)=;;LT]EM[f < hC j #qLG8^ 	 C '//\5F5F5J/KL  rL   	from_timeto_timec                 j   t         j                  j                         }t         j                   j                  ||       } t         j                   j                  ||      }t        j                  dd      |j	                         k(  r|t        j
                  d      z  }| |k\  rt        dd       | |fS )u  
        Нормализует интервал времени и проверяет его на корректность.
        Так как у datetime нет времени 24:00,
        то время окончания 00:00 конвертируется в 00:00 следующего дня,
        как будто это интервал, например, 18:00 - 24:00

        Args:
            from_time (Time, optional): время начала интервала. Defaults to None.
            to_time (Time, optional): время окончания интервала. Defaults to None.

        Returns:
            Tuple[Datetime, Datetime]: дата и время начала, дата и время окончания
        r      hoursuo   Время начала должно быть раньше времени окончания интервалаTabort)r*   r/   todaycombinetimer+   	cmf_alert)rW   rX   r_   s      r-   normalize_time_intervalz#CmfCalendar.normalize_time_interval  s      ##%%%--eY?	##++E7;==A',,.0x))33G  H  PT  U'!!rL   c                 ~    | r|syt         j                  j                  | |      \  } }|| z
  j                         dz  S )u?  
        Вычисляет в минутах интервал времени

        Args:
            from_time (Time, optional): время начала. Defaults to None.
            to_time (Time, optional): время окончания. Defaults to None.

        Returns:
            int: минуты
        r   <   )modelsr   rc   total_seconds)rW   rX   s     r-   get_interval_minutesz CmfCalendar.get_interval_minutes"  sC     #//GG	SZ[	7)#224r99rL   	exclusionzmodels.CmfCalendarExcludec                    g }d}|j                   j                  }|j                  j                  }|j                  }|j                  }|j
                  dk(  r(|j                  dk(  rd}| j                  |||      }||fS |j
                  dk(  r0d}| j                  ||||j                  |j                        }||fS |j
                  dk(  r;d	}| j                  ||||j                  |j                  |j                  
      }||fS |j
                  dk(  r&d}| j                  |||||j                        }||fS |j
                  dk(  r1d}| j                  |||||j                  |j                        }||fS |j
                  dk(  rEd}t        d      D cg c]  }t        |d| d      s| }	}| j                  |||||	      }||fS |j
                  dk(  r%|j                  dk7  rd}| j                  ||||      }||fS c c}w )uw  
        Расчитывает и возвращает исключительные дни и приоритет исключения
        Приоритеты исключений (7-самый высокий, 1-самый низкий):
            7 - Ежедневно (каждый день)
            6 - Ежегодно (в указанный день)
            5 - Ежегодно (по позиции дня недели месяца)
            4 - Ежемесячно (в указанный день)
            3 - Ежемесячно (по позиции дня недели)
            2 - Еженедельно
            1 - Ежедневно (каждый N день)

        Args:
            exclusion (CmfCalendarExclude): исключение

        Returns:
            Tuple[int, List[Date]]: приоритет, список дат
        NrK   r   r   every_year_dayr   )r9   r0   every_year_week_dayr   )r9   r1   r2   every_month_dayr   )r0   every_month_week_dayr   )r1   r2   rP   r   r2   F)rM   )period_start_datevalueperiod_end_daterF   repeat_timesrepeat_typerK   rV   r9   r0   month_week_positionmonth_day_weekrS   r'   getattrrP   )
clsri   r)   priorityrC   rD   rF   rE   r,   rM   s
             r-   calc_excluded_dayszCmfCalendar.calc_excluded_days5  sh   & 0066
,,22!!((  K/I4D4D4IH==Xw?DD ~C ""&66H>>*h(19CVCV " XD< ~9 ""&;;H>>*h(1+4+H+H.7.F.F " HD2 ~+ ""&77H??:x#)Y5H5H # JD$ ~! ""&<<H??:x&,5,I,I/8/G/G # ID ~ ""l2H#(8\awyKPQsBSUZ/[\H\>>*hRZ>[D ~ ""k1i6F6F!6KH==XwGD~ ]s   H
2H
c                 Z   t               }t        j                  j                  dd| g       t        j                  j                  dd| gg dg dddd|gdd	|ggd
d|gd
d	|ggdd	|gd
d|ggggdg      }|D ]K  }t        j                  j                  |      \  }}|D ]"  }||cxk  r|k  sn |j                  |       $ M t        j                  j                  dd| gg dg dddd|gdd	|ggd
d|gd
d	|ggdd	|gd
d|ggggdd
g      }	|	D ]f  }
t        |
j                  |      }t        |
j                  |      }|}||k  s7|j                  |       |t        j                   d      z  }||k  r0h t#        |      D ]"  }t        j                  j%                  | |       $ y)u  
        Для календаря у которого задан parent_calendar
        рассчитываем CmfCalendarDay только по рабочим неделями и исключениям, у которых есть временные ограничения
        parent==filter)ro   !=N)rq   r   NORro   >=<=rq   r   r~   fieldsr   rH   N)setrf   CmfCalendarDaybulk_deleteCmfCalendarExcludelistr   ry   addCmfCalendarWorkWeekslistmaxro   minrq   r*   r+   sortedrecalc_date)selfr#   r$   candidate_dates
exclusionsri   _	days_listd	workweeksworkweekstartendcurrents                 r-   _recalc_exceptions_rangez$CmfCalendar._recalc_exceptions_rangew  s3   
 %))(D$1G)H ..334&1/)4<?RTXZb>cd'z:=NPTV^<_`)4<?PRVX`>ab		 5 4 

 $ 	+I!--@@KLAy +.h.#''*+	+ ..444&1/)4<?RTXZb>cd'z:=NPTV^<_`)4<?PRVX`>ab		 ():; 5 
	 " 	6H22J?Eh..9CGS.##G,8--155 S.		6 ( 	4A**43	4rL   r>   c           	      b   d}g }|j                         d }t        j                  j                  |ddgg ddd|gdd	|gg
      }d}|D ](  }| j	                  |      \  }	}
|	||
v s|	|kD  s%|	}|}* |rT|j
                  j                  }|j                  j                  }|dk(  r|j                  d |j                  D               nt        j                  j                  |ddgdd|gdd	|gg
      }|rt        || d      j                  dk(  r|j                  ddg       |j                  }|syt        || d      j                  }t        || d      j                  }|dk(  r$|j                  fd|j                  D               t        j                  j                  ||      }|sQt        j                  ||      }|_        |j"                  |_        |j$                  |_        |j&                  |_        ||_        ||_        ||_        |j/                          |S )u   
        Пересчет указанного дня календаря

        Args:
            calendar (CmfCalendar): объект календаря
            date (Date): дата

        Returns:
            NoReturn
        Nr4   r   intervals.*rs   r   Nro   r   rq   r   r{   r   r~   r   workc              3      K   | ]N  }|j                   j                  j                  d       |j                  j                  j                  d       g P yw%H:%MN)rW   rp   strftimerX   .0intervals     r-   	<genexpr>z*CmfCalendar.recalc_date.<locals>.<genexpr>  sN      !@%- #+"4"4":":"C"CG"LhN^N^NdNdNmNmnuNv!w !@s   AA_typedefaultdefault_workweek.*default_workweek.intervals.*_intervals_total_minutesc              3      K   | ]g  }|j                   j                  k(  rL|j                  j                  j                  d       |j                  j                  j                  d       g i ywr   )day_weekrp   rW   r   rX   )r   r   rO   s     r-   r   z*CmfCalendar.recalc_date.<locals>.<genexpr>  sc      !f%-(BSBSBYBY]dBd #+"4"4":":"C"CG"LhN^N^NdNdNmNmnuNv!w !fs   A-A0r{   r/   )rO   rf   r   r   ry   exclude_typerp   intervals_total_minutesextend	intervalsr   getrv   load_fieldsdefault_workweekr   r   r8   r9   r4   day_typeinterval_total_minutesinterval_jsonsave)rw   r>   r/   r4   r   day_numr   exclusion_priorityri   rx   excluded_daysr   r   calendar_dayrO   s                 @r-   r   zCmfCalendar.recalc_date  sz    	,,.y/ ..33'+$dD1"D$/ 4 

 # 	 I&)&<&<Y&G#Hm}$4F)F%-"	  ''--H%(%@%@%F%F"6!   !@14!@ @ ,,00]+,dD9<MtUY;Z[ 1 C '#'%'89??9L$$&:<Z%[\//swiu$56<<H%,SWI=U2V%W%]%]"6!   !f14!f f ,,00t0L!00t0LL$+L! $		L!%L#xxL (.D+%."rL   Tback_recalcc                 (   |?t         j                   j                         j                         }|j                  dd      }|&|t	        d      z   t        j
                  d      z
  }| j                  ||      D ]  }| j                  ||        y)u$  
        Пересчет дней календаря
        Если интервал не задан, делает пересчет от начала текущего года +2 года, итого 3 года

        Args:
            calendar (CmfCalendar): объект календаря
            date_start (Date, optional): начальная дата
            date_end (Date, optional): конечная дата
            back_recalc (bool, optional): пересчет назад только текущего года
        Nr   rU   r   )yearsrH   )r*   r_   r/   r:   r   r+   r.   r   )rw   r>   r#   r$   r   r_   r/   s          r-   recalc_calendar_dayzCmfCalendar.recalc_calendar_day  s     %%++-224EQA6J!M$::X=O=OUV=WWHOOJ9 	,DOOHd+	,rL   r    z&type,intervals,intervals_total_minutesc                 x    t        j                  t        j                  |d            }| j	                  ||      S )u  
        Получает день календаря

        Args:
            calendar (Union[str, CmfCalendar, CmfType]): календарь
            date (Date): дата

        Returns:
            day (dict): информация о дне календаря
        r   )sysinterncmfutilget_obj_id_by_any_get_day)rw   r>   r/   calendar_ids       r-   get_dayzCmfCalendar.get_day  s0     jj!:!:8]!ST||K..rL   c                  X    t        dd        t        j                  j                          y )NCmfCalendar:day_cache_clear)cmf_emit_server_eventrf   r   _day_cache_clear_kwargss    r-   day_cache_clearzCmfCalendar.day_cache_clear(  s    ;TB++-rL   r   c                      t         j                  j                  j                          t         j                  j                  j                          t         j                  j                  j                          y N)rf   r   r   cache_clear_day_cache_int_internclear_day_cache_data_internr   s    r-   r   zCmfCalendar._day_cache_clear.  sL     	##//10066811779rL   i  )maxsizer   calendar_namec                    t         j                  j                  dd| gdd|ggg d      }|st         j                  j                  dd| gg d      }|s|j                  }|rA|j
                  r5t         j                  j                  dd|j
                  gdd|ggg d      }|st        d	|d
d| dd       t         j                  j                  t        j                  |j                        t        d |j                  D              t         j                  j                  j                  |j                  |j                              }t         j                  j                   j                  ||      S )N	parent_id=r/   )r   r   r   r   idr|   )parent_calendar_idnamez--u	   День z%d.%m.%Yu*    не найден в календаре "uO   ". Попробуйте запустить пересчет календаря.Tr]   c              3   |   K   | ]4  }t        j                  |d          t        j                  |d         f 6 yw)r   r   N)r   r   r   s     r-   r   z'CmfCalendar._get_day.<locals>.<genexpr>Z  s7      3 HQK(#**Xa[*AB3s   :<)rf   r   sgetr   r   r   rb   r    r   r   r   tupler   r   
setdefaultr   r   )r   r/   r   r4   r>   dds         r-   r   zCmfCalendar._get_day8  sq    ##(( #{3fc45HIJ ) 

 ))..tT;6OX|.}H  (H77++00(#x/J/JKfVZ\`MabR 1  Id8_4^_l^m nj krvx ''JJs||$ 3 # 1 13 4 44??@Z@Z\_\v\vw
 !!88CCBKKrL   r8   c                 v   |)t         j                   j                         j                  }n@t        |t         j                        st        |t         j                         r|j                  }t        j                  t        |      dd      }t        j                  t        |      dd      }t               }|}||k  rX|j                         |j                  |j                  |j                  ddg d||<   |t        j                  d      z  }||k  rX|j                  dd	g       |j                  }t        j                  j                  |d
dgddd|gdd|ggdd|gdd|ggdd|gdd|ggg      }|j!                         D ]  \  }	}
|	j                         }d| }t#        || d      j$                  }t#        || d      j$                  }||
d<   ||
d<   |dk(  s]|j&                  D cg c]e  }|j(                  j$                  |k(  rJ|j*                  j$                  j-                  d      |j.                  j$                  j-                  d      gg c}|
d<    |D ]^  }|j0                  j$                  }||j2                  k  s*d}g }|j                         }d| }t#        || d      j$                  }|dk(  r|t        j                  d      z  }a|dk(  rt#        || d      j$                  }|j&                  D cg c]e  }|j(                  j$                  |k(  rJ|j*                  j$                  j-                  d      |j.                  j$                  j-                  d      gg }}|j5                  |      }|r||d<   ||d<   ||d<   |t        j                  d      z  }||j2                  k  r5a t        j6                  j                  |d
dgg dddd|gdd|ggdd|gdd|ggdd|gdd|gggg      }|D cg c]#  }|j8                  r| j;                  |      |fz   % }}t=        |      D ]  \  }}}d}g }|j>                  j$                  }|dk(  rw|j@                  j$                  }|j&                  D cg c]L  }|j*                  j$                  j-                  d      |j.                  j$                  j-                  d      gN }}|D ]%  }	|j5                  |	      }|s||d<   ||d<   ||d<   '  t        jB                  j                  ||d
g      }|D ]  }|jE                  |j                  j$                  d      }
|
s,|
j5                  dg       jG                          |
j!                         D ]  \  }}tI        |||        |jJ                  s~|jM                  d        |j!                         D ]Q  \  }	}
t        jC                  ||	      }|
j!                         D ]  \  }}tI        |||        |jM                          S yc c}w c c}w c c}w c c}w ) uQ  
        Расчитывает все дни года с учетом рабочих недель и исключений и сохраняет их в БД

        Args:
            calendar (CmfCalendar): объект календаря
            year (Union[str, int, Date, Datetime], optional): год. Defaults to None.
        Nr   r      r   )r   r8   r9   r4   r   r   r   rH   r   r   r   r   r   ro   r   r   rq   r   r4   r   r   r   r   r   r   r   r   r   )r{   r8   r   T	only_datar   )'r*   nowr8   
isinstancer/   r(   dictrO   r9   r4   r+   r   r   rf   r   r   itemsrv   rp   r   r   rW   r   rX   ro   rq   r   r   rs   ry   r   r   r   r   popsortsetattr
is_changedr   )rw   r>   r8   start_date_yearend_date_yeardays_of_yearrJ   r   r   r/   day_datarO   r   r   r   r   r   current_period_dater   day_of_yearr   ri   excluded_datesr   datescalendar_daysr   
field_namerp   s                                r-   calc_one_yearzCmfCalendar.calc_one_yearc  s    <$$((*//Dhmm,
4ARAR0S99D"--D	1a8 c$iR8 v&m+(002$))%++#'' *+!#*L& H..A66L m+ 	24RST#44..33'%t_=@SUY[h?ij#T?;>OQUWd=ef%t_=@QSWYf?gh	 4 	
	 +002 	ND(llnGG9oG/G9E1BCIIH%,-='Jb?c%d%j%j"#+HZ 1GH-.6! %5$>$>- (BSBSBYBY]dBd ''--66w?AQAQAWAWA`A`ahAij-)	 " 	BH"*"<"<"B"B%)A)AA)*&	-557y/"8y->?EEy('8+=+=1+EE'v%-4X'Jb?c-d-j-j* )1(:(:!$h>O>O>U>UY`>` "++11::7CXEUEUE[E[EdEdelEmn!I !
 +../BC.6K
+<RK 893<K0#x'9'9q'AA#1 &)A)AA	B< ..33'+)4ADWY]_lCmn'?BSUY[hAij)4ADUW[]jCkl	 4 

  ,64'&22 00;ylJ 4 4 $*.#9 	=Aui%&"I --33H6!)2)J)J)P)P& %.$7$7  ''--66w?AQAQAWAWA`A`ahAij	   =*..t4.6K
+<RK 893<K0=	=& --22(WZV[2\) 	6L#''(9(9(?(?FH_b1668)1)9 =%JL*e<=  ** %%%5	6 +002 	 ND(!00t0LL%-^^%5 9!
Ej%89 	 k-,!:4s   /A*X'
A*X,(X1AX6
back_yearsforcec                    | j                  g d       |t        | j                        }|t        k  s	|t        kD  rt        dt         dt         d       | j                  s|syt        j                  j                         j                  }|r||z
  n|}|t        | j                        z   }| j                  rdt        j                  t        |      dd      }t        j                  t        |dz
        dd	      }| j                  ||       || _        || _        nd}t!        ||      D ]i  }	|s t        j                  t        |	      dd      }t"        j$                  j'                  | |	       t        j                  t        |	      dd	      | _        k || _        | j)                          t+        t"        j,                  j.                  d
| j0                  j2                  i       d| _        | j5                  d       y)u  
        Пересчитывает дни календаря.
        Пересчет начинается от текущего года вперед на количество лет,
        указанных в параметре calc_num_years календаря.
        Если в параметре back_years указано положительное число, то пересчет начнется с прошлых лет.
        Например:
            back_years = 3
            calc_num_years = 5
            текущий год - 2023
            Будут пересчитаны года с 2020 по 2027 включительно

        Args:
            force (bool, optional): принудительный пересчет дней календаря. Defaults to False.
            back_years (int, optional): количество прошлых лет. Defaults to 0.
        )dirtycalc_num_yearscalc_num_back_yearsparent_calendarNu7   Параметр back_years должен быть от u    до Tr]   r   r   r   r   )kwargsFr   )r   r(   r  MIN_CALC_NUM_BACK_YEARSMAX_CALC_NUM_BACK_YEARSrb   r  r*   r   r8   r  r  r/   r   	calc_from
calc_untilr'   rf   r   r   r   schedule_deferred_jobCmfGanttTaskrecalc_gantt_tasks_by_calendarr   rp   r   )
r   r   r   current_year	from_yearto_yearr#   r$   r  r8   s
             r-   r!   zCmfCalendar.recalc_calendar  s     	^_T556J//:@W3WIJaIbbh  jA  iB  C
 

e((,,.331;L:-	T%8%8!99!s9~q!<J}}S1%5r2>H))*h?'DN&DOIi1 C  (c$iA >I""00t<"*--D	2r"B	C
 'DN 	 	>>!477==1	

 
		D	!rL   from_dtto_dtc                 2    | j                  | ||      }|dz  S )u  
        Получает дельту рабочего времени в секундах между начальной и конечной датой и временем

        Args:
            from_dt (datetime): дата и время начала диапазона
            to_dt (datetime): дата и время конца диапазона

        Returns:
            work_timedelta (int): дельта рабочего времени в секундах
        re   )get_duration_minutes)r   r  r  minutess       r-   get_work_timedeltazCmfCalendar.get_work_timedelta8  s"     ++D'5A|rL   c                    d }d}t        j                  t        j                  t        |j                  xs d                  }|j	                         }|j	                         }	||	k  rr| j                  ||      }
|xr( ||j	                         k(  xs ||j	                         k(  }|
j                  dk7  r|s|t        j                  d      z  }o|r|}|
}|j                  dk7  r{||j	                         k(  r|t        j                  d      z  }n,||j	                         k(  r|t        j                  d      z  }| j                  ||      }|j                  dk7  r{|}
||j	                         k7  r=||j	                         k7  r*||
j                  z  }|t        j                  d      z  }Q|
j                  D ]  }t         j                   j                  |d   d      j                         }t         j                   j                  |d   d      j                         }t         j                   j                  |||      }t         j                   j                  |||      }|j                         t        j                  dd      k(  r|t        j                  d      z  } |||||      }||z  } |t        j                  d      z  }||	k  rr|S )	u  
        Получает продолжительность рабочего времени в минутах из указанного диапазона дат

        Args:
            calendar (CmfCalendar): объект календаря
            from_dt (datetime): дата и время начала диапазона
            to_dt (datetime): дата и время конца диапазона

        Returns:
            minutes_sum (int): сумма минут
        c                 |    t        | |      }t        ||      }||k  rt        ||z
  j                         dz        S y)Nre   r   )r   r   r(   rg   )r  r  interval_startinterval_endr   r   s         r-   	intersectz3CmfCalendar.get_duration_minutes.<locals>.intersectT  sA    0Ee\*Cs{C%K6682=>>rL   r   secondsr   r   rH   r   tzinfo)r*   timezoner+   r(   r/   r   typer   r   strptimera   r`   )rw   r>   r  r  force_include_endsr  minutes_sumtzrJ   rD   r4   force_includecur_datecur_dayr   rW   rX   r  r  inters                       r-   r  z CmfCalendar.get_duration_minutesF  s   	 x11#h>O>O>TST:UVW||~::<h&++h5C.sLGLLN4R4rVbfkfpfpfrVrMxx6!- 2 2 :: (llf,#w||~5 H$6$6A$>>%5 H$6$6A$>>!kk(H=G llf, w||~-,%**,2Ns::: 2 2 ::MM %$--66x{GLQQS	"++44Xa['JOOQ!)!2!2!:!:<[]!:!^'0088wWY8Z$$&(--1*== H$6$6A$>>L!'5.,Ou$% H..A66LK h&N rL   durationc                    |s|S t        j                  t        j                  t        |j                  xs d                  }d}|dk  rd}t	        |      }|j                         }|dkD  r| j                  ||      }|s|j                  nt        t        |j                              }|D ]9  }	t         j                   j                  |	d   d      j                         }
t         j                   j                  |	d   d      j                         }t         j                   j                  ||
|      }t         j                   j                  |||      }|j                         t        j                  dd      k(  r|t        j                  d      z  }|st        ||      n|}|rt        ||      n|}|||k  rt        ||z
  j                         d	z        ndz  }|dk  s: n |t        j                  |sdnd
      z  }|dkD  r|r$t        j                  t	        |            z   }|S t        j                  t	        |            z
  }|S )u$  
        Рассчитывает дату и время на основе длительности от указанной даты и времени

        Args:
            calendar (CmfCalendar): объект календаря
            from_dt (Datetime): дата и время от которой производится расчет
            duration (int, optional): длительность в минутах. Defaults to 0.

        Returns:
            to_dt (Datetime): рассчитанная дата и время
        r   r  FTr   r   r  rH   re   r5   )r  )r*   r  r+   r(   absr/   r   r   r   reversedr!  ra   r`   r   r   rg   )rw   r>   r  r)  r$  reverserJ   r4   r   r   rW   rX   r  r  r   r   r  s                    r-   get_date_by_durationz CmfCalendar.get_date_by_duration  s    Nx11#h>O>O>TST:UVWa<G8}H||~l++h5C-4$x?V:WI% $--66x{GLQQS	"++44Xa['JOOQ!)!2!2!:!:<[]!:!^'0088wWY8Z$$&(--1*== H$6$6A$>>L<CG^44;c'<0us{Cu ; ; = BCXYYq= H..WA"MML' l* "X%7%7H%NNE  !8#5#5c(m#LLErL   c                 V    |s|S | j                  ||d      }| j                  ||d      S )un   Если dt вне рабочего интервала, возвращает начало следующегоr   r5   )r.  )rw   r>   dt
dt_forwards       r-   get_nearest_work_timez!CmfCalendar.get_nearest_work_time  s5     I--hA>
''*bAArL   c                 r   t         j                  j                  | |j                               }t	        j
                  t	        j                  t        | j
                  xs d                  }|j                  }t        |      dz
  }|D ]  }t        j                  j                  |d   d      j                         }t        j                  j                  |d   d      j                         }t        j                  j                  |j                         ||      }	t        j                  j                  |j                         ||      }
|	j                         t	        j                  dd      k(  r)|
j                         t	        j                  dd      k(  r y|
j                         t	        j                  dd      k(  rHt        j                  j                  |
t        j                  j                  j                         |      }
||	k\  r||
k  r y||	k  r y||
k\  r|dk(  r y|dz  } y)	u=   
        Вычисляет флаг calendar_paused
        r>   r/   r   r  r   r   r  FT)rf   r   r   r/   r*   r  r+   r(   r   lenr!  ra   r`   r   )r>   
check_dater4   r$  r   r,   r   rW   rX   r  r  s              r-   get_sla_cycle_calendar_pausedz)CmfCalendar.get_sla_cycle_calendar_paused  s      (((AR(Sx11#h>O>O>TST:UVWMM		NQ! 	H ))228A;HMMOI''00!gFKKMG%..66z7H)\^6_N#,,44Z__5FXZ4[L""$a(;;@Q@Q@SW_WdWdefhiWj@j  "hmmAq&99'0088xGXGXG\G\GaGaGcln8o^+
\0I ~-|+6FA3	4 rL   c                    t         j                  j                  | |j                               }t	        j
                  t	        j                  t        | j
                  xs d                  }|j                  }d}t        |      dz
  }|D ]  }t        j                  j                  |d   d      j                         }t        j                  j                  |d   d      j                         }	t        j                  j                  |j                         ||      }
t        j                  j                  |j                         |	|      }|
j                         t	        j                  dd      k(  rX|j                         t	        j                  dd      k(  r1|t	        j                  d      z  }|j                  ddd	      }|} n|j                         t	        j                  dd      k(  rHt        j                  j                  |t        j                  j                  j                         |      }||
k\  r	||k  r|} n||
k  r|
} n||k\  r|dk(  r n|dz  } t        j                  j                  |t        j                  j                  j                         |      }|t	        j                  d
      z  }|st        j!                  | |      }|S )uX   
        Вычисляет next_time_update - сл дата пересчета
        r4  r   r  Nr   r   r  r[   )minutesecondmicrosecondrH   r>   r6  )rf   r   r   r/   r*   r  r+   r(   r   r5  r!  ra   r`   r:   r   r   get_sla_cycle_next_time_update)r>   r6  r4   r$  r   resultr,   r   rW   rX   r  r  s               r-   r=  z*CmfCalendar.get_sla_cycle_next_time_update  s      (((AR(Sx11#h>O>O>TST:UVWMM		NQ! "	H ))228A;HMMOI''00!gFKKMG%..66z7H)\^6_N#,,44Z__5FXZ4[L ""$a(;;@Q@Q@SW_WdWdefhiWj@jh00q99
'//qPQ/R
#   "hmmAq&99'0088xGXGXG\G\GaGaGcln8o^+
\0I &~-'|+6 FAE"	H &&..z8;L;L;P;P;U;U;W`b.c
h((a00
 ??^h?iFrL   z	@minutelyr   )	only_once
system_jobschedulerx   c                  >   t         j                   j                         } dd| gg dg dg}g d}d\  }}	 t        j                  j	                  |||||z   g      }|sy ||z  }|D ]  }|j
                  |_        t        j                  |j                  j                  |j
                  j                        |_        t        j                  |j                  j                  |j
                  j                        |j
                  _        |j                           )	Nnext_time_updater   )	stop_timer   NULL)r   r   T)	sla_goalzsla_goal.calendarzsla_goal.calendar.timezonecodepause_interval_stop_timepause_interval_start_timelast_time_updaterC  calendar_paused)r   d   )r~   r   slicer<  )r*   r   rf   CmfSDeskSlaCycler   rC  rJ  r   r7  rF  r>   rp   rK  r=  r   )r   r~   r   r   limitcyclescycles          r-   celery_minutely_hookz CmfCalendar.celery_minutely_hook.  sB    ##%  s+&"
: u,,11W\^cfk^kVl1mFUNE ).)?)?&(3(Q(Q[`[i[i[r[r  @E  @V  @V  @\  @\(Q  )]%/:/Y/Ychcqcqczcz  HM  H^  H^  Hd  Hd/Y  0e&&,

 rL   c                   & ddl m} ddlm} ddd}t        j                  j                         j                  }||dz   f}|D ]k  } |t        j                  dd	t        |            j                  d
      }|j                         sFt        |dd      5 }t        j                  |j                               }	ddd       	j!                  d      }
||
k7  rt"        j%                  d|
 d| d|        g }|	j!                  d      D ci c]  }|d   |d    }}|	j!                  d      }|	j!                  d      }|D ]   }|j!                  d      &t        j                  j'                  |
 d& d      j)                         }|j*                   dt,        |j.                      d|j                   }t0        j2                  j5                  dd| gg dg dd d!d|gd"d|gggd#$      }|r|j!                  d%      }|j!                  d&      }|r|j!                  |      }n|j!                  |      }d}t7        t9        &fd'|      d      }t7        t9        &fd(|      d      }|r|d)   }n|r|d*   }|rft        j                  j'                  |
 d| d      j)                         }|d+|j*                   dt,        |j.                      d|j                   z  }d,|d-d.| j:                   }d/|| d0| d1|||j.                  |j*                  |j=                         |j*                  dz
  d2z  d3d4
}t0        j2                  j!                  d5d6d7| gd8gd39      }|st0        j3                  | :      }|j?                         D ]  \  }}tA        |||        |jB                  rd#|_!        |jD                  r|jG                  d3;       |dk7  r|jI                  d<g       | jI                  d=g       | jJ                  }rj=                         }n|j=                         }|jL                  } t0        jN                  jQ                  ||d8g>      }! || |!      }"|"D ]{  \  }#}$|$rL|#st0        jS                  |:      }#|$jT                  |#_*        |$jV                  |#_+        |$jX                  |#_,        n	|#rd3|#_!        |#jD                  sj|#jG                  d3;       } n<|jI                  d?g       |jL                  D ]  }#d3|#_!        |#jG                  d3;        |j[                          |j]                          |jG                  d3;       |j_                  |       # t0        j2                  jQ                  d5d@|gd5d6d,| dAgg dBgC      }%|%D ]  }|ja                  d3D        n | jI                  dEg       | jc                          | jG                  d3;       y# 1 sw Y   .xY wc c}w )Fu  
        Метод для кнопки "Загрузить праздники".
        Добавляет в исключения календаря выходные/празничные дни из файла в формате JSON.
        Исключения добавляются на текущий и следующий год (при наличии соответствующих файлов).
            - файлы с данными находятся в каталоге /opt/eva-app/cmf/contrib/calendar/
            - имя файла должено содержать только год (например, 2024.json)
        Добавления не происходит, если пользователь уже добавил исключение на такую же дату.
        При повторном выполнении метода происходит перезагрузка/восстановление/удаление,
        если поменялись данные в файле.
        r   )zip_longest)Pathu   Выходной деньu   Рабочий день)r   r   r   contribr>   z.jsonrzutf-8)encodingNr8   u   Год (uL   ) указанный в файле не соответствует году u    в имени файла holidaysr   r   	transfersr   r/   .z%Y.%m.%d r{   r   )rs   r   rK   )rF   r   r   r   ro   rq   F)r~   is_autor   holidayc                 ,    | j                  d      k(  S )Nfromr   itemdate_s    r-   <lambda>z+CmfCalendar.load_holidays.<locals>.<lambda>  s    TXXf=MQV=V rL   c                 ,    | j                  d      k(  S )Ntora  rb  s    r-   re  z+CmfCalendar.load_holidays.<locals>.<lambda>  s    488D>U;R rL   rg  r`  u    за exclude_z%Y_%m_%d:rK   z ()r   T)
rs   rG  r   ro   rq   r9   r0   ru   rt   r]  rG  LIKE%r   )r~   r   include_deleted)r{   r   r   r   )r{   r   r   r   zNOT INz_%)r]  r   Tr}   )r   r  )2	itertoolsrT  pathlibrU  r*   r   r8   config
CMF_FOLDERstrwith_suffixexistsopenjsonloadsreadr   loggingwarningr!  r/   r4   MONTHS_SHORTr9   rf   r   r   nextr~   rG  rO   r   r   cmf_deletedr   r   r   r   r   CmfCalendarWorkWeekIntervalr   CmfCalendarExcludeIntervalrW   rX   interval_minutes_calc_intervals_total_minutes_calc_exclude_typerI   delete_set_as_dirty)'r   rT  rU  	day_typesr  r   r8   	file_pathfcalendar_datacalendar_yearexclude_codesr^  rY  rZ  r   	date_datar/   date_strexcluder   r   transfertransfer_fromtransfer_totransfer_daterG  exclude_datafieldrp   r   rO   exclude_intervalsworkweek_intervalsr   exclude_intervalworkweek_intervalexcludesrd  s'                                         @r-   r"   zCmfCalendar.load_holidaysM  sR    	*  +(
	
  ((,,.33|a/0 V	+DV..	:s4yQ]]^efI##%iw7 51 $

1668 45 *--f5M}$(=/ :MMQFRlmvlw!y zMFSFWFWXbFcd7wv6dHd%))+6I!%%g.E" x+	!f-((11]O1UG2LjY^^`"hhZqdjj)A(B!DII;O !3388!3-/PRd 3S$?BSUXZ^A_` " 9   %==0#--	2#<<0D$==2D#H$(0VXa)bdh$iM"&v.RT]'^`d"eK$#0#6$#.v#6(0(9(9(B(B,oQxj9:)GGKtv & f]->->,?qmNaNaAb@ccderewewdx$yy "$x$))= $/ #fBxj2)-'+!ZZ!%&*lln,0HHqLQ+>#  !3377"FavJ75$( 8 
 $77t7DG$0$6$6$8 3LE5GUE23 &&*/G'%%LL4L0q= ''8$$&8%9:'+'<'<$$"/"7"7"9"&,,.(/(9(9%)/)K)K)P)P/!( #u *Q *& !,,=?Q RI?H B;(*;,#3393T3T\c3T3d 09J9T9T,67H7P7P,4@Q@b@b,=-;?,8+66,11D1AB ''6,3,=,= >(7;(4(---=> 557**,t,$$T*qx+x 0055=18D6!45&>5 H
 $ +T*+kV	+p 	'#		D	!i5 5 es   $W(W5(W2	c                     d| _         y)u   
        Помечает, что календарь необходимо пересчитать и сбрасывает кэш дней
        TN)r  r   s    r-   r  zCmfCalendar._set_as_dirty  s     
rL   c                    | j                   j                  sy| j                   st        dd       nG| j                  r;t	        | j                  j
                  t        j                        rt        dd       d| j                   d}t        j                  j                  dd	| j                  gg d
gdg      }|r+d|_         |j                  d       d|j                   d| }t        |       y)uX   
        Изменяет флаг "Календарь по умолчанию"
        Nu   Для сброса флага "Календарь по умолчанию" вы должны установить его у любого другого календаря.Tr]   u   Личным календарям пользователей нельзя устанавливать флаг "Календарь по умолчанию".uf   Во всех новых проектах будет использоваться календарь ""r   r   )
is_defaultr   Tr  r   Fr   u^   Сбросили флаг "Календарь по умолчанию" у календаря "z". )r  r   rb   r{   r   rp   rf   	CmfPersonr   r   r   r   r   )r   msgcurrent_default_calendars      r-   _set_is_defaultzCmfCalendar._set_is_default  s    )) z BFG {{z$++*;*;V=M=MN  x  @D  Evw{  xA  xA  wB  BC  D#)#5#5#9#9tTWW%) !> $: $
  $27$/$))D)9..F.K.K-LCPSuVC#rL   c                     | j                   j                  rd| _         | j                  j                  rd| _        | j                  j                  rd| _        yy)u}   
        Исправляет нулевые значения, если приходит null выставляет 0
        r   N)r  is_nullr  r  r  s    r-   fix_null_valuezCmfCalendar.fix_null_value"  sK     ==  DM&&"#D##++'(D$ ,rL   c                 *    t         |          g dz   S )N)r  r  r  )supersave_preload_fields)r   	__class__s    r-   r  zCmfCalendar.save_preload_fields/  s    w*,/dddrL   c                    | j                   rst        | dd       rt        j                  j	                  | j
                  g d      }|j                  | _        |j                  | _        |j                  | _        |j                  D ]  }|j                         }| |_        d|_        |j                  d       |j                  dg       |j                  D ]+  }|j                         }||_        |j                  d       - |j                   r|j"                  r|| _         |j&                  D ]w  }|j                         }	| |	_        |	j                  d       |j                  dg       |j                  D ]+  }|j                         }|	|_        |j                  d       - y nt(        j(                  j+                         j-                         j.                  }
t1        t(        j(                  j+                  |
      j3                         j5                               | _        t        j7                  | d	      }t9        d
      D ]  }t;        |d| dd        |j                  d       || _        | j=                          | j?                          t1        | j                        t@        kD  rtC        dt@         dd       t1        | j                        tD        k  rtC        dtD         dd       t1        | j                        tF        kD  rtC        dtF         dd       t1        | j                        tH        k  rtC        dtH         d       | j                  jJ                  s| j                  jJ                  r| jM                          | jN                  jJ                  r,| jN                  | k(  rtC        dd       | jQ                          tS        | 4  |i |S )Ntemplate)r   zworkweeks.*zexclusions.*)r   r   FTr   r   u   По умолчанию)r{   r   r   r4   r   weekenduS   Количество лет расчета не должно быть больше u    летr]   uS   Количество лет расчета не должно быть меньше u	    годаue   Количество лет расчета в прошлое не должно быть больше ue   Количество лет расчета в прошлое не должно быть меньше ua   Календарь не может быть родительским для самого себя)*is_newrv   rf   r   r   r  r  r  r  r   cloner{   systemr   r   r   ro   rq   r   r   r*   r   
astimezoner  r(   	utcoffsetrg   r   r'   r   r  r  MAX_CALC_NUM_YEARSrb   MIN_CALC_NUM_YEARSr  r  r   r  r  r   r  )r   argsr  template_calendartemplate_workweeknew_workweektemplate_intervalnew_intervaltemplate_exclusionnew_exclusionr$  r   r,   r  s                r-   r   zCmfCalendar.save2  s   ;;tZ.$*$6$6$:$:}}? %; %! !2 : :&7&F&F#+<+P+P():)D)D =%#4#:#:#<L*.L'*/L' %%%5%11=/B->-H-H :)'8'>'>'@.:+$))D)9:
 (99,B^B^0<-= +<*F*F 	:&$6$<$<$>M+/M(!&&&6&22M?C-?-I-I :)'8'>'>'@.;+$))D)9:	: &&**,779@@ #H$5$5$9$9"$=$G$G$I$W$W$Y Z "55THa5bq AAHA3eni@A-(0%t""#&88kl~k  @G  H  PT  Ut""#&88kl~k  @I  J  RV  Wt''(+BBw  yP  xQ  QX  Y t''(+BBw  yP  xQ  R
 ))T-E-E-P-P **##t+}  FJ  K  "w|T,V,,rL   c              #   4  K   d }dd}| j                  dg       d}|}t        g       }d }	d}
d}	 |s5| j                  rdd|gdd	|t        j                  d
      z   gg} || j                  |d      } || |d      }||z   }|ri }|D ]/  }|j
                  | k(  s|j                  |vs!|||j                  <   1 t        |j                               D ];  }||   }|j                  dk(  s|s|j                  ||fv s+|j                  |       = nSddd|gg dgg}|r.|
s|j                  dd|g       |r|s|j                  dd|g       |j                   || |             |s\| j                  j                         }d }|sd| j                   d}|S d| j                   d| j                  j                          }|S |j                         }|j                  |k(  r;|j                  dk7  r* ||      }|j                   |_        |j"                  |_        d}
|j                  |k(  r`|j                  dk7  rO|	r#|	j                   |_        |	j"                  |_        n* ||      }|j                   |_        |j"                  |_        d}|j                  dk(  r|}	| t$        j'                  |j                  j(                  t$        j*                  j-                               t        j                  d      z   j                         }|dz  }w)Nc                 h    t        t        |             D ]  }| |   j                  dk(  s| |   c S  y )Nr   )r'   r5  r   )bufferr,   s     r-   _get_next_work_dayz1CmfCalendar.work_days.<locals>._get_next_work_day  s6    3v;' %!9%%/!!9$%rL   Tc                 ~    t        dd| g|gg ddg      }|rddg|d<   t        j                  j                  d	i |S )
Nr{   r|   )r/   r   r   r   zparent.timezoner/   )r~   r   order_byr      rM   )r   rf   r   r   )r>   date_filterdo_slicer  s       r-   _get_calendar_daysz1CmfCalendar.work_days.<locals>._get_calendar_days  sO    !42K@i F
 #$b'w((--777rL   r  r   Fr/   r   <r   rH   )r  r   r   )r   r|   r   r|   u   Календарь "u   " не рассчитан.u   " рассчитан до r   )T)r   r   r  r*   r+   r{   r/   r   keysr   rI   r   r	  loadr   popleftr   r   Datetimer`   rp   r   ra   )r   rC   r"  finish_dater  r  n	next_dater  prev_work_daystart_date_givenfinish_date_givenr  parent_days	self_daysr)   days_by_dater4   date_keyday_candidater	  messagework_daynext_work_days                           r-   	work_dayszCmfCalendar.work_days  s/    	%
	8 	+,-	r !''$*D)#<vsIX`XjXjprXsLs>t"uK"4T5I5I;af"gK 24u UI&2D')#' =C"zzT1SXX\5Q9<SXX 6=
 )/|/@/@/B(C =H,8,BM - 6 6& @$6=;M;MR\^iQj;j &m <= $(64*CE_)`"aK)/'..j/IJ&/@'..k/JKMM"4T;"GH!__113
! 4TYYK?YZG  !5TYYK?YZ^ZiZiZnZnZpYqrG~~'H}}
*$$.$6v$>M-:-H-HH*6C6Z6ZH3#' }}+$$.$1>1L1L.:G:^:^7(:6(B1>1L1L.:G:^:^7$(!  F* (N!))(--*=*=x||?P?P?RSV^VhVhnoVppvvxIFAG s   B+L.AL2LHLc           
         | j                  dg       | j                  rt        dd       t        j                  j                  | dg      }|r=dj                  |D cg c]  }d|j                   d c}      }t        d	| d       |j                  d
d      s3t        j                  j                  |       }|rt        d| dd       t        j                  j                  | ddg      }|rTdj                  |D cg c])  }d|j                  j                   d|j                   d+ c}      }	t        d|	 d       t        
| 8  |i |S c c}w c c}w )Nr  u   Нельзя удалить календарь по умолчанию. Сначала назначьте любой другой календарь, как календарь по умолчанию.Tr]   r   )r>   r   z, r  uk   Невозможно удалить календарь, он используется в проектах: from_person_deleteF)r>   uY   Невозможно удалить календарь, он используется у u    пользователейzparent.namez: ue   Невозможно удалить календарь, он используется в целях: )r   r  rb   rf   
CmfProjectr   joinr   r   r  countCmfSDeskSlaGoalr{   r  r  )r   r  r  projectsprojectprojects_strperson_count	sla_goalsslasla_goals_strr  s             r-   r  zCmfCalendar.delete  s   ,(?? Z " $$))4)I99%Rg',,q&9%RSL  D  EQ  DR  S "zz.6!++1141@Lu  wC  vD  D_  ` $& **//v}F]/^	 IIU^&_c3::??*;2chhZq'I&_`M}  L  ~M  N " w~t.v.. &S '`s    E.E )NNN)NNr   )NNr   N)NNr   NNN)NNNNNN)NN)NNTr   )NF)F)r   )A__name__
__module____qualname__r   r   ui_meta_skipapi_methodsstaticmethodDater   r.   r(   rB   r   rK   rP   rS   rV   Timer	   r  rc   rh   classmethodry   r   r   r   boolr   r   r    r
   rr  cmfr   CmfTyper   r   on_server_eventr   r   r   r   r   r   r   r!   r  r  r.  r2  r7  r=  cmf_deferred_jobrR  r"   r  r  r  r  r   r  r  __classcell__)r  s   @r-   r   r      sh   ++88<GL**66:
 
K
 5 5 5$ 5 5 CGOSD S 03ILX\ < JN !d d C &*4j B _`)-(t (t (S (Y\ (!#Y(26t*( (T LP6:=A1 1 1c 11031!17:1FJ4j1 1f KO7;<@-t -t -S --14- -69-EI$Z- -^ 2604"4 ")-"9>x?Q9R" "6 : :d :c : :$ ?+F ?5QTVZ[_V`Q`Ka ? ?B44l N= N N N N` FJ04,= ,(,,?C,)-,9A, ,. $LMG/uS-9K9K%KL /TX /]d / / . .
 23: 4 :
 tLc L Lhsm LW^ L  L> >BS ] S !#sD(":;S GOS  S j="# ="T ="h ="~( 8   05DM DH DU] D:=D DL @A2M 2&.2:=2FN2 2h B B & &P 7 7r VXY Z :p"d:)eM-^]~/ /rL   r   )"r>   r6   r*   ra   	functoolsr   collectionsr   r   typingr   r   r   r	   r
   r   r   pytzcmf.includecommon.fieldsr   dateutil.relativedeltar   r   r{  r  r/   r  r  r  r  r  r  r   r  rL   r-   <module>r     s        ) C C 
   & 4 HHHhH	 }}}}    Y/,** Y/rL   