
    oih                       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 G d dej:                        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   дек)                        	   
         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	 	 dHded	ed
ededef
d       Ze	 	 dIdededededee   f
d       Ze	 	 dJdededededee   dee   fd       Ze	 	 	 dKdedededed	ed
ed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eef   fd       ZedMd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	 	 dNd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*+      dOd,e!ded-e,e!   defd.              Z-e	 dOdd d/e e!eeef   defd0       Z.dPd1ed2edefd3Z/d4ed5edefd6Z0e	 dQdd d4ed5edefd7       Z1e	 dRdd d4ed8edefd9       Z2ed:        Z3ed;        Z4e e5d!d!d<d=>      d?               Z6d@ Z7dA Z8dB Z9dC Z: fdDZ; fdEZ<dF Z= fdGZ> xZ?S )S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-   r.   r/   r0   days_in_monthr2   calendarweeksweekday_of_weekss
             r+   _get_day_by_position_in_monthz)CmfCalendar._get_day_by_position_in_month1   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   )rA   rB   rC   rD   r'   current_dates         r+   	every_dayzCmfCalendar.every_dayP   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]: список дат
        Tr3   )weekdayr   F)r=   )r   r   rG   )	rA   rB   rC   rD   rK   r'   rH   rM   r2   s	            r+   
every_weekzCmfCalendar.every_weekr   s    & G!M"R&$AA# "]7%CC*$'1x"'KK$ M77L   rJ   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r.   r/   r0   r   r   )r6   r7   )r   r@   rG   r7   r6   r8   )rA   rB   rC   rD   r.   r/   r0   r'   rH   r2   r7   r6   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! $ rJ   r7   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   r7   r2   rP   )r6   )r8   r   r@   rG   r6   )
rA   rB   rC   r7   r.   r/   r0   r'   rH   r2   s
             r+   
every_yearzCmfCalendar.every_year   s    4 G!))1)=;;LT]EM[f < hC j #qLG8^ 	 C '//\5F5F5J/KL  rJ   	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)rU   rV   r]   s      r+   normalize_time_intervalz#CmfCalendar.normalize_time_interval  s      ##%%%--eY?	##++E7;==A',,.0x))33G  H  PT  U'!!rJ   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   ra   total_seconds)rU   rV   s     r+   get_interval_minutesz CmfCalendar.get_interval_minutes  sC     #//GG	SZ[	7)#224r99rJ   	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]]: приоритет, список дат
        NrI   r   r   every_year_dayr   )r7   r.   every_year_week_dayr   )r7   r/   r0   every_month_dayr   )r.   every_month_week_dayr   )r/   r0   rN   r   r0   F)rK   )period_start_datevalueperiod_end_daterD   repeat_timesrepeat_typerI   rT   r7   r.   month_week_positionmonth_day_weekrQ   r%   getattrrN   )
clsrg   r'   priorityrA   rB   rD   rC   r*   rK   s
             r+   calc_excluded_dayszCmfCalendar.calc_excluded_days0  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                    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 ]z  }
t        |
j                  j                  |      }t        |
j                  j                  |      }|}||k  sK|j                  |       |t!        j"                  d      z  }||k  r0| t%        |      D ]"  }t        j                  j'                  | |       $ y)u  
        Для календаря у которого задан parent_calendar
        рассчитываем CmfCalendarDay только по рабочим неделями и исключениям, у которых есть временные ограничения
        parent==filter)rm   !=N)ro   r}   NORrm   >=<=ro   r   r|   fieldsr   rF   N)setrd   CmfCalendarDaybulk_deleteCmfCalendarExcludelistr   rw   addCmfCalendarWorkWeekslistmaxrm   rn   minro   r(   r)   sortedrecalc_date)selfr!   r"   candidate_dates
exclusionsrg   _	days_listd	workweeksworkweekstartendcurrents                 r+   _recalc_exceptions_rangez$CmfCalendar._recalc_exceptions_ranger  s?   
 %))(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288*EEh..44h?CGS.##G,8--155 S.		6 ( 	4A**43	4rJ   r<   c           	      \   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                  }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
        Nr2   r   intervals.*rq   r}   Nrm   r   ro   r   ry   r   r|   r   workc              3      K   | ]N  }|j                   j                  j                  d       |j                  j                  j                  d       g P yw%H:%MN)rU   rn   strftimerV   .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_weekrn   rU   r   rV   )r   r   rM   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ry   r-   )rM   rd   r   r   rw   exclude_typern   intervals_total_minutesextend	intervalsr   getrt   load_fieldsdefault_workweekr   r   r6   r7   r2   day_typeinterval_total_minutesinterval_jsonsave)ru   r<   r-   r2   r   day_numr   exclusion_priorityrg   rv   excluded_daysr   r   calendar_dayrM   s                 @r+   r   zCmfCalendar.recalc_date  st    	,,.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+%."rJ   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   rS   r   )yearsrF   )r(   r]   r-   r8   r   r)   r,   r   )ru   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+	,rJ   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)ru   r<   r-   calendar_ids       r+   get_dayzCmfCalendar.get_day  s0     jj!:!:8]!ST||K..rJ   c                  X    t        dd        t        j                  j                          y )NCmfCalendar:day_cache_clear)cmf_emit_server_eventrd   r   _day_cache_clear_kwargss    r+   day_cache_clearzCmfCalendar.day_cache_clear   s    ;TB++-rJ   r   c                      t         j                  j                  j                          t         j                  j                  j                          t         j                  j                  j                          y N)rd   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9rJ   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                  }|r7|j
                  r+t         j                  j                  |j
                  ||      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   idrz   )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>N  s7      3 HQK(#**Xa[*AB3s   :<)rd   r   sgetr   r   r   r   r`   r   r   r   r   tupler   r   
setdefaultr   r   )r   r-   r   r2   r<   dds         r+   r   zCmfCalendar._get_day0  sS    ##(( #{3fc45HIJ ) 

 ))..tT;6OX|.}H  (H77))2283N3NPTVcdd	$x0Z[hZi jf gnrt ''JJs||$ 3 # 1 13 4 44??@Z@Z\_\v\vw
 !!88CCBKKrJ   r6   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   r6   r7   r2   r   r   r   rF   r   r   r   r   r~   rm   r   r   ro   r   r2   r   r   r   r   r   r   r   r   r   )ry   r6   r   T	only_datar   )'r(   nowr6   
isinstancer-   r&   dictrM   r7   r2   r)   r   r   rd   r   r   itemsrt   rn   r   r   rU   r   rV   rm   ro   r   r   rq   rw   r   r   r   r   popsortsetattr
is_changedr   )ru   r<   r6   start_date_yearend_date_yeardays_of_yearrH   r   r   r-   day_datarM   r   r   r   r   r   current_period_dater   day_of_yearr   rg   excluded_datesr   datescalendar_daysr   
field_namern   s                                r+   calc_one_yearzCmfCalendar.calc_one_yearW  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   | j                  g d       |t        | j                        }|dk  s|dkD  rt        d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%                          d| _        | j'                  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_calendarNr   r   u@   Параметр back_years должен быть от 0 до 10Tr[   r   r   r   Fr   )r   r&   r  r`   r   r(   r   r6   r   r  r-   r   	calc_from
calc_untilr%   rd   r   r   r   r   )
r   r   r   current_year	from_yearto_yearr!   r"   r  r6   s
             r+   r   zCmfCalendar.recalc_calendar  ss     	^_T556J>Z"_X`de

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 	
		D	!rJ   from_dtto_dtc                 2    | j                  | ||      }|dz  S )u  
        Получает дельту рабочего времени в секундах между начальной и конечной датой и временем

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

        Returns:
            work_timedelta (int): дельта рабочего времени в секундах
        rc   )get_duration_minutes)r   r  r	  minutess       r+   get_work_timedeltazCmfCalendar.get_work_timedelta#  s"     ++D'5A|rJ   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)Nrc   r   )r   r   r&   re   )r  r	  interval_startinterval_endr   r   s         r+   	intersectz3CmfCalendar.get_duration_minutes.<locals>.intersect?  sA    0Ee\*Cs{C%K6682=>>rJ   r   secondsr   r   rF   r   tzinfo)r(   timezoner)   r&   r-   r   typer   r   strptimer_   r^   )ru   r<   r  r	  force_include_endsr  minutes_sumtzrH   rB   r2   force_includecur_datecur_dayr   rU   rV   r  r  inters                       r+   r  z CmfCalendar.get_duration_minutes1  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 rJ   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  rF   rc   r3   )r  )r(   r  r)   r&   absr-   r   r   r   reversedr  r_   r^   r   r   re   )ru   r<   r  r!  r  reverserH   r2   r   r   rU   rV   r  r  r   r   r	  s                    r+   get_date_by_durationz CmfCalendar.get_date_by_durationx  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rJ   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)rd   r   r   r-   r(   r  r)   r&   r   lenr  r_   r^   r   )r<   
check_dater2   r  r   r*   r   rU   rV   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 rJ   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 - сл дата пересчета
        r(  r   r  Nr   r   r  rY   )minutesecondmicrosecondrF   r<   r*  )rd   r   r   r-   r(   r  r)   r&   r   r)  r  r_   r^   r8   r   r   get_sla_cycle_next_time_update)r<   r*  r2   r  r   resultr*   r   rU   rV   r  r  s               r+   r1  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rJ   z	@minutelyr   )	only_once
system_jobschedulerv   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_updater7  calendar_paused)r   d   )r|   r   slicer0  )r(   r   rd   CmfSDeskSlaCycler   r7  r>  r   r+  r:  r<   rn   r?  r1  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&&,

 rJ   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)encodingNr6   u   Год (uL   ) указанный в файле не соответствует году u    в имени файла holidaysr   r   	transfersr   r-   .z%Y.%m.%d ry   r   )rq   r   rI   )rD   r   r   r~   rm   ro   F)r|   is_autor  holidayc                 ,    | j                  d      k(  S )Nfromr   itemdate_s    r+   <lambda>z+CmfCalendar.load_holidays.<locals>.<lambda>w  s    TXXf=MQV=V rJ   c                 ,    | j                  d      k(  S )NtorU  rV  s    r+   rY  z+CmfCalendar.load_holidays.<locals>.<lambda>x  s    488D>U;R rJ   r[  rT  u    за exclude_z%Y_%m_%d:rI   z ()r   T)
rq   r;  r   rm   ro   r7   r.   rs   rr   rQ  r;  LIKE%r   )r|   r   include_deleted)ry   r   r   r   )ry   r   r   r   zNOT INz_%)rQ  r   Tr{   )r   r   )2	itertoolsrH  pathlibrI  r(   r   r6   config
CMF_FOLDERstrwith_suffixexistsopenjsonloadsreadr   loggingwarningr  r-   r2   MONTHS_SHORTr7   rd   r   r   nextr|   r;  rM   r   r   cmf_deletedr   r   r   r   r   CmfCalendarWorkWeekIntervalr   CmfCalendarExcludeIntervalrU   rV   interval_minutes_calc_intervals_total_minutes_calc_exclude_typerG   delete_set_as_dirty)'r   rH  rI  	day_typesr  r   r6   	file_pathfcalendar_datacalendar_yearexclude_codesrR  rM  rN  r   	date_datar-   date_strexcluder   r   transfertransfer_fromtransfer_totransfer_dater;  exclude_datafieldrn   r   rM   exclude_intervalsworkweek_intervalsr   exclude_intervalworkweek_intervalexcludesrX  s'                                         @r+   r    zCmfCalendar.load_holidays/  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+   rx  zCmfCalendar._set_as_dirty  s     
rJ   c                 Z   | j                   j                  sy| j                   s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[   uf   Во всех новых проектах будет использоваться календарь ""r   r}   )
is_defaultr   Tr  r   Fr   u^   Сбросили флаг "Календарь по умолчанию" у календаря "z". )	r  r   r`   r   rd   r   r   r   r   )r   msgcurrent_default_calendars      r+   _set_is_defaultzCmfCalendar._set_is_default  s     )) z BFG ww{  xA  xA  wB  BC  D#)#5#5#9#9tTWW%) !> $: $
  $27$/$))D)9..F.K.K-LCPSuVC#rJ   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$ ,rJ   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drJ   c                 N   | 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                        dkD  rtA        dd       t1        | j                        dk  rtA        dd       t1        | j                        dkD  rtA        dd       t1        | j                        dk  rtA        dd       | j                  jB                  s| j                  jB                  r| jE                          | jF                  jB                  r| jI                          tK        | 4  |i |S )Ntemplate)r   zworkweeks.*zexclusions.*)r   r   FTr   r   u   По умолчанию)ry   r   r   r2   r   weekend   u\   Количество лет расчета не должно быть больше 30 летr[   r   u]   Количество лет расчета не должно быть меньше 1 годаr   un   Количество лет расчета в прошлое не должно быть больше 10 летr   uf   Количество лет расчета в прошлое не должно быть меньше 0)&is_newrt   rd   r   r   r  r  r   r  r   clonery   systemr   r   r   rm   ro   r   r   r(   r   
astimezoner  r&   	utcoffsetre   r   r%   r   r  r  r`   r   rx  r  r   r  )r   argskwargstemplate_calendartemplate_workweeknew_workweektemplate_intervalnew_intervaltemplate_exclusionnew_exclusionr  r   r*   r  s                r+   r   zCmfCalendar.save  sV   ;;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""#b(t  }A  Bt""#a'u  ~B  Ct''(2-  G  OS  Tt''(1,~  GK  L))T-E-E-P-P **  "w|T,V,,rJ   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%   r)  r   )bufferr*   s     r+   _get_next_work_dayz1CmfCalendar.work_days.<locals>._get_next_work_dayZ  s6    3v;' %!9%%/!!9$%rJ   Tc                 ~    t        dd| g|gg ddg      }|rddg|d<   t        j                  j                  d	i |S )
Nry   rz   )r-   r   r   r   zparent.timezoner-   )r|   r   order_byr      rA   )r   rd   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7rJ   r  r   Fr-   r   <r  rF   )r  r   r~   )r   rz   r   rz   u   Календарь "u   " не рассчитан.u   " рассчитан до r   )T)r   r   r  r(   r)   ry   r-   r   keysr   rG   r   r  loadr   popleftr   r   Datetimer^   rn   r   r_   )r   rA   r  finish_dater  r  n	next_dater  prev_work_daystart_date_givenfinish_date_givenr  parent_days	self_daysr'   days_by_dater2   date_keyday_candidater  messagework_daynext_work_days                           r+   	work_dayszCmfCalendar.work_daysX  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       t        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        
| 4  |i |S c c}w c c}w )Nr  u   Нельзя удалить календарь по умолчанию. Сначала назначьте любой другой календарь, как календарь по умолчанию.Tr[   r   )r<   r   z, r  uk   Невозможно удалить календарь, он используется в проектах: )r<   uY   Невозможно удалить календарь, он используется у u    пользователейzparent.namez: ue   Невозможно удалить календарь, он используется в целях: )r   r  r`   rd   
CmfProjectr   joinr   	CmfPersoncountCmfSDeskSlaGoalry   r  rw  )r   r  r  projectsprojectprojects_strperson_count	sla_goalsslasla_goals_strr  s             r+   rw  zCmfCalendar.delete  st   ,(?? Z " $$))4)I99%Rg',,q&9%RSL  D  EQ  DR  S "''--t-<qr~q  @[  \ " **//v}F]/^	 IIU^&_c3::??*;2chhZq'I&_`M}  L  ~M  N " w~t.v.. &S '`s    E	5.E)NNN)NNr   )NNr   N)NNr   NNN)NNNNNN)NN)NNTr   )NF)F)r   )@__name__
__module____qualname__r   r   ui_meta_skipapi_methodsstaticmethodDater   r,   r&   r@   r   rI   rN   rQ   rT   Timer	   r  ra   rf   classmethodrw   r   r   r   boolr   r   r   r
   rf  cmfr   CmfTyper   r   on_server_eventr   r   r   r   r   r   r   r   r  r  r&  r+  r1  cmf_deferred_jobrF  r    rx  r  r  r  r   r  rw  __classcell__)r  s   @r+   r   r      sR   ++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 K= K K K KZ FJ04,= ,(,,?C,)-,9A, ,. $LMG/uS-9K9K%KL /TX /]d / / . .
 23: 4 :
 tLc L Lhsm LW^ L  L6 >BS ] S !#sD(":;S GOS  S j4"# 4"T 4"h 4"l( 8   05DM DH DU] D:=D DL @A2M 2&.2:=2FN2 2h & &P 7 7r VXY Z :p"d4)eE-N]~/ /rJ   r   )r<   r4   r(   r_   	functoolsr   collectionsr   r   typingr   r   r   r	   r
   r   r   pytzcmf.includecommon.fieldsr   dateutil.relativedeltar   r   ro  r  r-   r  r  r   r  rJ   r+   <module>r     s        ) C C 
   & 4 HHHhH	 }}}}t/,** t/rJ   