
    oi                        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T 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j        Zej        Z G d dej                  ZdS )    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                   J    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	 	 dLd	ed
edededef
d            Ze	 	 dMdededededee         f
d            Ze	 	 dNdededededee         dee         fd            Ze	 	 	 dOdedededed
edededee         fd            Ze	 	 	 dPdedededed
edededee         fd            Ze	 	 dQdededeeef         fd            ZedQd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	 	 dRd!d deded$edef
d%            Z ed&d'          Zed!e e!d e"j#        j$        f         d	edefd(            Z%ed)             Z&e e'd*          d+                         Z(i Z)i Z*e e+d,-          dSd.e!d	ed/e,e!         defd0                        Z-e	 dSd!d d1e e!eeef         defd2            Z.dTd4ed5edefd6Z/d7ed8edefd9Z0e	 dUd!d d7ed8edefd:            Z1e	 dVd!d d7ed<edefd=            Z2ed>             Z3ed?             Z4e e5d#d#d@dAB          dC                         Z6dD Z7dE Z8dF Z9dG Z: fdHZ; fdIZ<dJ Z= fdKZ> xZ?S )WCmfCalendar)DayDatarecalc_calendarload_holidays
date_startdate_endreturnc              #      K   t          t          || z
  j                  dz             D ]}| t          j        |          z   V  dS )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"   s]       sHz17881<== 	5 	5Ax1!4444444	5 	5    Ndate	month_daypositionday_of_weekc                 F    |rDt          j         j         j                  d         }||k     r|}                     |          }nXt          j                    }|                     j         j                  } fd|D             }|dk     r||         n|d         }|S )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   )dayc                 L    g | ] }|         j         j         k    |         !S  )month).0weekr.   r1   s     r+   
<listcomp>z=CmfCalendar._get_day_by_position_in_month.<locals>.<listcomp>K   s4    iii$4CTCZ^b^hChChD-ChChChr-   r   )cl
monthrangeyearr6   replaceCalendarmonthdatescalendar)	r.   r/   r0   r1   days_in_monthr3   calendarweeksday_of_weekss	   `  `     r+   _get_day_by_position_in_monthz)CmfCalendar._get_day_by_position_in_month1   s    $  		OM$)TZ@@CMy(()	,,9,--CC{}}H//	4:FFEiiiii%iiiL,4qLL,x((l2>NC
r-   r   
start_dateend_daterepeatsperiodc                     g }|d}| }|r9||dz  }n||k    rn*|                     |           |t          |          z  }|9|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]: список дат
        NTr   r'   )appendr   )rF   rG   rH   rI   r'   current_dates         r+   	every_dayzCmfCalendar.every_dayP   sx    " G! 	71((KK%%%Mv6666L  	7 r-   weekdaysc                    g }|d}| t          t          d                    z   }|r^|D ]F}|t          |          z   }|| k    r'||dz  }n
||k    rd} n|                    |           |s nG|t          |          z  }|^|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]: список дат
        NTr:   )weekdayr   F)rC   )r   r   rL   )	rF   rG   rH   rI   rO   r'   rM   rQ   r3   s	            r+   
every_weekzCmfCalendar.every_weekr   s    & G!M"R&&$A$A$AA 	8#  "]7%C%C%CC*$$'1x"'KK$$$ E M7777L  	8  r-   c                     g }|d}| }|rt                               ||||          }	|	| k    r$||dz  }n|	|k    rnP|                    |	           |j        dz
  |z   }
|j        |
dz  z   }|
dz  dz   }
|                    ||
          }||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]: список дат
        NTr/   r0   r1   r   r   )r=   r6   )r   rE   rL   r6   r=   r>   )rF   rG   rH   rI   r/   r0   r1   r'   rM   r3   r6   r=   s               r+   every_monthzCmfCalendar.every_month   s    4 G! 	H;;LT]EM[f < h hC j  #qLGG8^^C    &*V3E$u{2DBJNE'//T/GGL!  	H$ r-   r6   c                    g }|d}|                      |d          }|rht                              ||||          }	|	| k    r$||dz  }n|	|k    rn5|                    |	           |                     |j        dz             }|h|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_
        NTr   r6   r3   rT   )r=   )r>   r   rE   rL   r=   )
rF   rG   rH   r6   r/   r0   r1   r'   rM   r3   s
             r+   
every_yearzCmfCalendar.every_year   s    4 G!))1)== 	L;;LT]EM[f < h hC j  #qLGG8^^C   '//\5F5J/KKL  	L r-   	from_timeto_timec                 z   t           j                                        }t           j                             ||           } t           j                             ||          }t          j        dd          |                                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)rY   rZ   ra   s      r+   normalize_time_intervalz#CmfCalendar.normalize_time_interval  s      ##%%%--eY??	#++E7;;=A',,..00x)3333G  H  PT  U  U  U  U'!!r-   c                     | r|sdS t           j                            | |          \  } }|| z
                                  dz  S )u?  
        Вычисляет в минутах интервал времени

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

        Returns:
            int: минуты
        r   <   )modelsr   re   total_seconds)rY   rZ   s     r+   get_interval_minutesz CmfCalendar.get_interval_minutes  sR      	 	1#/GG	SZ[[	7)#2244r99r-   	exclusionzmodels.CmfCalendarExcludec                 >   g }d}j         j        }j        j        }j        }j        }j        dk    r&j        dk    rd}|                     |||          }n>j        dk    r(d}|                     |||j        j	                  }nj        dk    r-d	}|                     |||j        j
        j        
          }nӉj        dk    r"d}|                     ||||j	                  }nj        dk    r(d}|                     ||||j
        j                  }nsj        dk    r8d}fdt          d          D             }|                     |||||          }n0j        dk    r%j        dk    rd}|                     ||||          }||fS )uw  
        Расчитывает и возвращает исключительные дни и приоритет исключения
        Приоритеты исключений (7-самый высокий, 1-самый низкий):
            7 - Ежедневно (каждый день)
            6 - Ежегодно (в указанный день)
            5 - Ежегодно (по позиции дня недели месяца)
            4 - Ежемесячно (в указанный день)
            3 - Ежемесячно (по позиции дня недели)
            2 - Еженедельно
            1 - Ежедневно (каждый N день)

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

        Returns:
            Tuple[int, List[Date]]: приоритет, список дат
        NrN   r   r   every_year_dayr   )r6   r/   every_year_week_dayr   )r6   r0   r1   every_month_dayr   )r/   every_month_week_dayr   )r0   r1   rR   r   c                 <    g | ]}t          d | d          |S )r1   F)getattr)r7   r*   rk   s     r+   r9   z2CmfCalendar.calc_excluded_days.<locals>.<listcomp>i  s5    \\\awyBSPQBSBSUZ/[/[\\\\r-   )rO   )period_start_datevalueperiod_end_daterI   repeat_timesrepeat_typerN   rX   r6   r/   month_week_positionmonth_day_weekrU   r%   rR   )	clsrk   r'   priorityrF   rG   rI   rH   rO   s	    `       r+   calc_excluded_dayszCmfCalendar.calc_excluded_days0  s
   & 06
,2!( K//I4D4I4IH==Xw??DD"&666H>>*h(19CV " X XDD"&;;;H>>*h(1+4+H.7.F " H HDD "&777H??:x#)Y5H # J JDD"&<<<H??:x&,5,I/8/G # I IDD "l22H\\\\588\\\H>>*hRZ>[[DD"k11i6F!6K6KH==XwGGD~r-   c                 h   t                      }t          j                            dd| g           t          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 ]N}t          j                            |          \  }}|D ]'}||cxk    r|k    rn |                    |           (Ot          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 ]g}
t          |
j        |          }t          |
j        |          }|}||k    r3|                    |           |t          j        d          z  }||k    3ht#          |          D ]"}t          j                            | |           #dS )u  
        Для календаря у которого задан parent_calendar
        рассчитываем CmfCalendarDay только по рабочим неделями и исключениям, у которых есть временные ограничения
        parent==filter)rs   !=N)ru   r   NORrs   >=<=ru   r   r   fieldsr   rK   N)setrh   CmfCalendarDaybulk_deleteCmfCalendarExcludelistr   r|   addCmfCalendarWorkWeekslistmaxrs   minru   r(   r)   sortedrecalc_date)selfr!   r"   candidate_dates
exclusionsrk   _	days_listd	workweeksworkweekstartendcurrents                 r+   _recalc_exceptions_rangez$CmfCalendar._recalc_exceptions_ranger  s   
 %%))(D$1G)HHH .334&111///)4<?RTXZb>cd'z:=NPTV^<_`)4<?PRVX`>ab		 5 4 
 

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

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

        Returns:
            NoReturn
        Nr3   r   intervals.*rw   r   Nrs   r   ru   r   r~   r   r   r   workc              3      K   | ]B}|j         j                            d           |j        j                            d           gV  CdS %H:%MNrY   rt   strftimerZ   r7   intervals     r+   	<genexpr>z*CmfCalendar.recalc_date.<locals>.<genexpr>  sl       !@ !@%- #+"4":"C"CG"L"LhN^NdNmNmnuNvNv!w !@ !@ !@ !@ !@ !@r-   _typedefaultdefault_workweek.*default_workweek.intervals.*_intervals_total_minutesc              3      K   | ]R}|j         j        k    |j        j                            d           |j        j                            d           gV  SdS r   day_weekrt   rY   r   rZ   r7   r   rQ   s     r+   r   z*CmfCalendar.recalc_date.<locals>.<genexpr>  sr       !f !f%-(BSBY]dBdBd #+"4":"C"CG"L"LhN^NdNmNmnuNvNv!wBdBdBdBd!f !fr-   r~   r.   )rQ   rh   r   r   r|   exclude_typert   intervals_total_minutesextend	intervalsr   getrr   load_fieldsdefault_workweekr   r   r=   r6   r3   day_typeinterval_total_minutesinterval_jsonsave)rz   rB   r.   r3   r   day_numr   exclusion_priorityrk   r{   excluded_daysr   r   calendar_dayrQ   s                 @r+   r   zCmfCalendar.recalc_date  s    	,,..!// .33'+++$dD1"D$/ 4 
 

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

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

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

        Returns:
            day (dict): информация о дне календаря
        r   )sysinterncmfutilget_obj_id_by_any_get_day)rz   rB   r.   calendar_ids       r+   get_dayzCmfCalendar.get_day  s7     j!:!:8]!S!STT||K...r-   c                  b    t          dd            t          j                                         d S )NCmfCalendar:day_cache_clear)cmf_emit_server_eventrh   r   _day_cache_clear_kwargss    r+   day_cache_clearzCmfCalendar.day_cache_clear#  s.    ;TBBB++-----r-   r   c                      t           j        j                                         t           j        j                                         t           j        j                                         d S N)rh   r   r   cache_clear_day_cache_int_internclear_day_cache_data_internr   s    r+   r   zCmfCalendar._day_cache_clear)  sR     	#//11106688817799999r-   i  )maxsizer   calendar_namec                    t           j                            dd| gdd|ggg d          }|st           j                            dd| gg d          }|s|j        }|r7|j        r0t           j                            dd|j        gdd|ggg d          }|st          d	|d
d| dd           t           j                            t          j	        |j
                  t          d |j        D                       t           j        j                            |j        |j                            }t           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   | ]8}t          j        |d                    t          j        |d                   fV  9dS )r   r   N)r   r   r   s     r+   r   z'CmfCalendar._get_day.<locals>.<genexpr>U  sW       3 3 HQK((#*Xa[*A*AB3 3 3 3 3 3r-   )rh   r   sgetr   r   r   rd   r   r   r   r   tupler   r   
setdefaultr   r   )r   r.   r   r3   rB   dds         r+   r   zCmfCalendar._get_day3  s    #(( #{3fc45HIJJJ ) 
 

  	x)..tT;6OX|X|X|.}}H  . ( H7 +00(#x/JKfVZ\`MabRRR 1    x kdp k k_l k k krvx x x x ''Js|$$ 3 3 # 13 3 3 4 4 4??@Z\_\vww
 
 !8CCBKKKr-   r=   c                 	    |$t           j                                         j        }n;t          |t           j                  st          |t           j                   r|j        }t          j        t          |          dd          }t          j        t          |          dd          }t                      }|}||k    rL|                                |j        |j        |j	        ddg d||<   |t          j
        d          z  }||k    L|                    dd	g           |j        }t          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          }|                                D ]t\  }	}
|	                                d }t#          || d          j        }t#          || d          j        }||
d<   ||
d<   |dk    rfd|j        D             |
d<   u|D ]}|j        j        }||j        k    rd}g }|                                d }t#          || d          j        }|dk    r|t          j
        d          z  }_|dk    r+t#          || d          j        }fd|j        D             }|                    |          }|r||d<   ||d<   ||d<   |t          j
        d          z  }||j        k    Όt          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          } fd|D             }t1          |          D ]d\  }}}d}g }|j        j        }|dk    r|j        j        }d |j        D             }|D ](}	|                    |	          }|r||d<   ||d<   ||d<   )et          j                            ||d
g          }|D ]}|                    |j        j        d          }
|
rp|
                    dg                                            |
                                D ]\  }}t=          |||           |j        r|                     d !           |                                D ]`\  }	}
t                              ||	"          }|
                                D ]\  }}t=          |||           |                                  adS )#uQ  
        Расчитывает все дни года с учетом рабочих недель и исключений и сохраняет их в БД

        Args:
            calendar (CmfCalendar): объект календаря
            year (Union[str, int, Date, Datetime], optional): год. Defaults to None.
        Nr   r      r   )r   r=   r6   r3   r   r   r   rK   r   r   r   r   r   rs   r   r   ru   r   r3   r   r   r   r   r   c                     g | ]P}|j         j        k    |j        j                            d           |j        j                            d           gQS r   r   r   s     r+   r9   z-CmfCalendar.calc_one_year.<locals>.<listcomp>  sb     - - - (BSBY]dBdBd '-66w??AQAWA`A`ahAiAijBdBdBdr-   r   r   c                     g | ]P}|j         j        k    |j        j                            d           |j        j                            d           gQS r   r   r   s     r+   r9   z-CmfCalendar.calc_one_year.<locals>.<listcomp>  sb     ! ! !$h>O>UY`>`>` "+1::7CCXEUE[EdEdelEmEmn>`>`>`r-   r   c                 P    g | ]"}|j         	                    |          |fz   #S r5   )rw   r|   )r7   rk   rz   s     r+   r9   z-CmfCalendar.calc_one_year.<locals>.<listcomp>  sF     4 4 4'&24#00;;ylJ 4 4 4r-   c                     g | ]@}|j         j                            d           |j        j                            d           gAS r   r   r   s     r+   r9   z-CmfCalendar.calc_one_year.<locals>.<listcomp>  sV         '-66w??AQAWA`A`ahAiAij  r-   )r~   r=   r   T	only_datar   )!r(   nowr=   
isinstancer.   r&   dictrQ   r6   r3   r)   r   r   rh   r   r   itemsrr   rt   r   rs   ru   r   r   r   r   r   r   popsortsetattr
is_changedr   )rz   rB   r=   start_date_yearend_date_yeardays_of_yearrM   r   r   r.   day_datar   r   r   r   current_period_dater   day_of_yearr   excluded_datesr   datesrk   calendar_daysr   
field_namert   rQ   s   `                          @r+   calc_one_yearzCmfCalendar.calc_one_year^  s{    <$((**/DDhm,, 	
4AR0S0S 	9D"-D		1a88 c$iiR88 vv&m++(0022$)%+#' *+!#* *L& H.A6666L m++ 	24RSTTT#4.33'%t_=@SUY[h?ij#T?;>OQUWd=ef%t_=@QSWYf?gh	 4 	
 	
	 +0022 	 	ND(llnnG%GooG/G1B1B1BCCIH%,-='?c?c?c%d%d%j"#+HZ 1GH-.6!!- - - -$4$>- - -) " 	B 	BH"*"<"B%)AAA)*&	-5577)//"8->->->??Ey(('8+=1+E+E+EE'v%%-4X'?c?c?c-d-d-j*! ! ! !(0(:! ! !I
 +../BCC =.6K
+<RK 893<K0#x'9q'A'A'AA#1 &)AAA6 .33'+++)4ADWY]_lCmn'?BSUY[hAij)4ADUW[]jCkl	 4 
 

4 4 4 4+54 4 4 $*.#9#9 	= 	=Aui%&"I -3H6!!)2)J)P& $-$7  	  = =*..t44 =.6K
+<RK 893<K0= -22(WZV[2\\) 	6 	6L#''(9(?FFH 6_b1166888)1)9)9 = =%JL*e<<<<* 6 %%%555*0022 	  	 ND(!00t0LLL%-^^%5%5 9 9!
Ej%8888	  	 r-   F
back_yearsforcec                    |                      g d           |t          | j                  }|dk     s|dk    rt          dd           | j        s|sdS t
          j                                        j        }|r||z
  n|}|t          | j                  z   }| j	        rnt          j
        t          |          dd          }t          j
        t          |dz
            d	d
          }|                     ||           || _        || _        nd}t          ||          D ]o}	|s#t          j
        t          |	          dd          }t          j                            | |	           t          j
        t          |	          d	d
          | _        p|| _        |                                  t'          t          j        j        d| j        j        i           d| _        |                     d           dS )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   r   )kwargsFr   )r   r&   r  rd   r  r(   r   r=   r  r  r.   r   	calc_from
calc_untilr%   rh   r   r  r   schedule_deferred_jobCmfGanttTaskrecalc_gantt_tasks_by_calendarr   rt   r   )
r   r  r	  current_year	from_yearto_yearr!   r"   r  r=   s
             r+   r   zCmfCalendar.recalc_calendar  s     	^^^___T566J>>Z"__X`deeee
 	e 	F(,,..31;ML:--	T%8!9!99 	'!s9~~q!<<J}S1%5%5r2>>H))*h???'DN&DOOIi11 C C  ? (c$iiA > >I"00t<<<"*-D		2r"B"B&DN 	 	>!47=1	
 	
 	
 	

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

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

        Returns:
            work_timedelta (int): дельта рабочего времени в секундах
        rg   )get_duration_minutes)r   r  r  minutess       r+   get_work_timedeltazCmfCalendar.get_work_timedelta0  s%     ++D'5AA|r-   c                    d }d}t          j        t          j        t          |j        pd                              }|                                }|                                }	||	k    r|                     ||          }
|o/||                                k    p||                                k    }|
j        dk    r|s|t          j        d          z  }u|r|}|
}|j        dk    r||                                k    r|t          j        d          z  }n0||                                k    r|t          j        d          z  }|                     ||          }|j        dk    |}
||                                k    r<||                                k    r$||
j        z  }|t          j        d          z  }^|
j        D ]}t           j         	                    |d         d          
                                }t           j         	                    |d         d          
                                }t           j                             |||          }t           j                             |||          }|
                                t          j
        dd          k    r|t          j        d          z  } |||||          }||z  }|t          j        d          z  }||	k    |S )	u  
        Получает продолжительность рабочего времени в минутах из указанного диапазона дат

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

        Returns:
            minutes_sum (int): сумма минут
        c                     t          | |          }t          ||          }||k     r't          ||z
                                  dz            S dS )Nrg   r   )r   r   r&   ri   )r  r  interval_startinterval_endr   r   s         r+   	intersectz3CmfCalendar.get_duration_minutes.<locals>.intersectL  sQ    00Ee\**Cs{{C%K66882=>>>qr-   r   secondsr   r   rK   r   tzinfo)r(   timezoner)   r&   r.   r   typer   r   strptimerc   rb   )rz   rB   r  r  force_include_endsr"  minutes_sumtzrM   rG   r3   force_includecur_datecur_dayr   rY   rZ   r   r!  inters                       r+   r  z CmfCalendar.get_duration_minutes>  s   	 	 	 x1#h>O>TST:U:UVVVWW||~~::<<h&&++h55C.sLGLLNN4R4rVbfkfpfpfrfrVrMx6!!-! 2 : : ::  (lf,,#w||~~55 H$6A$>$>$>>%55 H$6A$>$>$>>!kk(H==G lf,, w||~~--,%**,,2N2Ns:: 2 : : ::M % %$-66x{GLLQQSS	"+44Xa['JJOOQQ!)!2!:!:<[]!:!^!^'088wWY8ZZ$$&&(-1*=*=== H$6A$>$>$>>L!	'5.,OOu$H.A6666LK h&&N r-   r   durationc                    |s|S t          j        t          j        t          |j        pd                              }d}|dk     rd}t	          |          }|                                }|dk    r|                     ||          }|s|j        n t          t          |j                            }|D ]\}	t           j         
                    |	d         d                                          }
t           j         
                    |	d         d                                          }t           j                             ||
|          }t           j                             |||          }|                                t          j        dd          k    r|t          j        d          z  }|st          ||          n|}|rt          ||          n|}|||k     r't          ||z
                                  d	z            ndz  }|dk    r n^|t          j        |sdnd
          z  }|dk    |r&|t          j        t	          |                    z   }n%|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%  rK   rg   r:   )r  )r(   r'  r)   r&   absr.   r   r   r   reversedr)  rc   rb   r   r   ri   )rz   rB   r  r1  r,  reverserM   r3   r   r   rY   rZ   r   r!  r   r   r  s                    r+   get_date_by_durationz CmfCalendar.get_date_by_duration  su     	Nx1#h>O>TST:U:UVVVWWa<<G8}}H||~~ll++h55C-4W$x?V?V:W:WI%  $-66x{GLLQQSS	"+44Xa['JJOOQQ!)!2!:!:<[]!:!^!^'088wWY8ZZ$$&&(-1*=*=== H$6A$>$>$>>L<CWG^4444;Mc'<000us{{Cu ; ; = = BCCCXYYq==E ! H.W4LAA"MMMML' ll*  	M"X%7H%N%N%NNEE 8#5c(mm#L#L#LLEr-   c                    t           j                            | |                                          }t	          j        t	          j        t          | j        pd                              }|j        }t          |          dz
  }|D ]}t          j        
                    |d         d                                          }t          j        
                    |d         d                                          }t          j                            |                                ||          }	t          j                            |                                ||          }
|	                                t	          j        dd          k    r.|
                                t	          j        dd          k    r dS |
                                t	          j        dd          k    rCt          j                            |
t          j        j                                        |          }
||	k    r	||
k     r dS ||	k    r dS ||
k    r	|dk    r dS |dz  }dS )	u=   
        Вычисляет флаг calendar_paused
        rB   r.   r   r#  r   r   r%  FT)rh   r   r   r.   r(   r'  r)   r&   r   lenr)  rc   rb   r   )rB   
check_dater3   r,  r   r*   r   rY   rZ   r   r!  s              r+   get_sla_cycle_calendar_pausedz)CmfCalendar.get_sla_cycle_calendar_paused  s     (((ARAR(SSx1#h>O>TST:U:UVVVWWM		NNQ! 	 	H )228A;HHMMOOI'00!gFFKKMMG%.66z7H7H)\^6__N#,44Z__5F5FXZ4[[L""$$a(;(;;;@Q@Q@S@SW_WdefhiWjWj@j@juu  ""hmAq&9&999'088xGXG\GaGaGcGcln8oo^++
\0I0I uu~--tt|++6644FAAur-   c                    t           j                            | |                                          }t	          j        t	          j        t          | j        pd                              }|j        }d}t          |          dz
  }|D ] }t          j        
                    |d         d                                          }t          j        
                    |d         d                                          }	t          j                            |                                ||          }
t          j                            |                                |	|          }|
                                t	          j        dd          k    r_|                                t	          j        dd          k    r4|t	          j        d          z  }|                    ddd	          }|} n|                                t	          j        dd          k    rCt          j                            |t          j        j                                        |          }||
k    r
||k     r|} n||
k    r|
} n||k    r|dk    r n|dz  }t          j                            |t          j        j                                        |          }|t	          j        d
          z  }|st                              | |          }|S )uX   
        Вычисляет next_time_update - сл дата пересчета
        r8  r   r#  Nr   r   r%  r]   )minutesecondmicrosecondrK   rB   r:  )rh   r   r   r.   r(   r'  r)   r&   r   r9  r)  rc   rb   r>   r   r   get_sla_cycle_next_time_update)rB   r:  r3   r,  r   resultr*   r   rY   rZ   r   r!  s               r+   rA  z*CmfCalendar.get_sla_cycle_next_time_update  s     (((ARAR(SSx1#h>O>TST:U:UVVVWWM		NNQ! "	 "	H )228A;HHMMOOI'00!gFFKKMMG%.66z7H7H)\^6__N#,44Z__5F5FXZ4[[L ""$$a(;(;;;@Q@Q@S@SW_WdefhiWjWj@j@jh0q9999
'//qPQ/RR
#   ""hmAq&9&999'088xGXG\GaGaGcGcln8oo^++
\0I0I &~--'|++66 EFAA&..z8;L;P;U;U;W;W`b.cc
h(a0000
 	j ??^h?iiFr-   z	@minutelyr   )	only_once
system_jobscheduler{   c                     t           j                                         } dd| gg dg dg}g d}d\  }}	 t          j                            |||||z   g          }|sd S ||z  }|D ]}|j        |_        t                              |j	        j
        |j        j        	          |_        t                              |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_updaterG  calendar_paused)r   d   T)r   r   slicer@  )r(   r   rh   CmfSDeskSlaCycler   rG  rN  r   r;  rJ  rB   rt   rO  rA  r   )r   r   r   r   limitcyclescycles          r+   celery_minutely_hookz CmfCalendar.celery_minutely_hook  sE    ##%%  s+&&&"""
: : : u	,11W\^cfk^kVl1mmF UNE  ).)?&(3(Q(Q[`[i[r  @E  @V  @\(Q  )]  )]%/:/Y/Ychcqcz  HM  H^  Hd/Y  0e  0e&,

	r-   c                 ~  & ddl m} ddlm} ddd}t          j                                        j        }||dz   f}|D ]} |t          j        dd	t          |                    
                    d
          }|                                sPt          |dd          5 }t                              |                                          }	ddd           n# 1 swxY w Y   |	                    d          }
||
k    r$t"                              d|
 d| d|            g }d |	                    d          D             }|	                    d          }|	                    d          }|D ]>}|                    d          &t          j                            |
 d& d                                          }|j         dt,          |j                  d|j         }t0          j                            dd| gg dg ddd d|gd!d|gggd"#          }|r|                    d$          }|                    d%          }|r|                    |          }n|                    |          }d}t7          t9          &fd&|          d          }t7          t9          &fd'|          d          }|r	|d(         }n
|r|d)         }|r_t          j                            |
 d| d                                          }|d*|j         dt,          |j                  d|j         z  }d+|d,d-| j         }d.|| d/| d0|||j        |j        |                                |j        dz
  d1z  d2d3
}t0          j                            d4d5d6| gd7gd28          }|st0                              | 9          }|                                D ]\  }}tA          |||           |j!        rd"|_!        |j"        r|#                    d2:           |dk    r|$                    d;g           | $                    d<g           | j%        }|r|                                }n|                                }|j&        } t0          j'        (                    ||d7g=          }! || |!          }"|"D ]o\  }#}$|$rB|#st0          )                    |9          }#|$j*        |#_*        |$j+        |#_+        |$j,        |#_,        n	|#rd2|#_!        |#j"        r|##                    d2:           pn=|$                    d>g           |j&        D ]}#d2|#_!        |##                    d2:            |-                                 |.                                 |#                    d2:           |/                    |           @t0          j        (                    d4d?|gd4d5d+| d@gg dAgB          }%|%D ]}|0                    d2C           | $                    dDg           | 1                                 | #                    d2:           dS )Eu  
        Метод для кнопки "Загрузить праздники".
        Добавляет в исключения календаря выходные/празничные дни из файла в формате JSON.
        Исключения добавляются на текущий и следующий год (при наличии соответствующих файлов).
            - файлы с данными находятся в каталоге /opt/eva-app/cmf/contrib/calendar/
            - имя файла должено содержать только год (например, 2024.json)
        Добавления не происходит, если пользователь уже добавил исключение на такую же дату.
        При повторном выполнении метода происходит перезагрузка/восстановление/удаление,
        если поменялись данные в файле.
        r   )zip_longest)Pathu   Выходной деньu   Рабочий день)r   r   r   contribrB   z.jsonrzutf-8)encodingNr=   u   Год (uL   ) указанный в файле не соответствует году u    в имени файла c                 ,    i | ]}|d          |d         S )r   r   r5   )r7   holidays     r+   
<dictcomp>z-CmfCalendar.load_holidays.<locals>.<dictcomp>b  s"    ddd7wvdddr-   holidays	transfersr  r.   .z%Y.%m.%d r~   r   )rw   r   rN   )rI   r   r   r   rs   ru   F)r   is_autor(  r^  c                 6    |                      d          k    S )Nfromr   itemdate_s    r+   <lambda>z+CmfCalendar.load_holidays.<locals>.<lambda>  s    TXXf=M=MQV=V r-   c                 6    |                      d          k    S )Ntorg  rh  s    r+   rk  z+CmfCalendar.load_holidays.<locals>.<lambda>  s    488D>>U;R r-   rm  rf  u    за exclude_z%Y_%m_%d:rN   z ()r   T)
rw   rK  r   rs   ru   r6   r/   ry   rx   rd  rK  LIKE%r   )r   r   include_deleted)r~   r   r   r   )r~   r   r   r   zNOT INz_%)rd  r   Tr   )r	  r  )2	itertoolsrX  pathlibrY  r(   r   r=   config
CMF_FOLDERstrwith_suffixexistsopenjsonloadsreadr   loggingwarningr)  r.   r3   MONTHS_SHORTr6   rh   r   r   nextr   rK  rQ   r   r   cmf_deletedr   r   r   r   r   CmfCalendarWorkWeekIntervalr   CmfCalendarExcludeIntervalrY   rZ   interval_minutes_calc_intervals_total_minutes_calc_exclude_typerL   delete_set_as_dirty)'r   rX  rY  	day_typesr  r   r=   	file_pathfcalendar_datacalendar_yearexclude_codesr`  ra  r  	date_datar.   date_strexcluder   r^  r   transfertransfer_fromtransfer_totransfer_daterK  exclude_datafieldrt   r   rQ   exclude_intervalsworkweek_intervalsr   exclude_intervalworkweek_intervalexcludesrj  s'                                         @r+   r    zCmfCalendar.load_holidays<  s    	*)))))       +(
 
	
  (,,..3|a/0 V	+ V	+DV.	:s4yyQQ]]^effI##%% iw777 51 $

16688 4 45 5 5 5 5 5 5 5 5 5 5 5 5 5 5 *--f55M}$$ !y= !y !yMQ!y !ymv!y !y z z zMddmFWFWXbFcFcdddH%))+66I!%%g..E" x+ x+	!f--(11]2L2LU2L2LjYY^^``"hOOdj)AOODIOO !388!3-/P/P/PRdRdRd 3S$?BSUXZ^A_` " 9     %==00#--	22 z#<<00DD$==22D#H$(0V0V0V0VXa)b)bdh$i$iM"&v.R.R.R.RT]'^'^`d"e"eK$ 7#0#6$ 7#.v#6 z(0(9(B(B,99x99:)G )GGKtvv & $y]->$y$ymNaAb$y$yerew$y$yy >$===$)== $/ #22x222)-'+!Z!%&*llnn,0HqLQ+>#    !377"FJJJ75$( 8  
  E$77t7DDG$0$6$6$8$8 3 3LE5GUE2222& 0*/G'% 1LL4L000q== ''888$$&8%9:::'+'<$$ 1"/"7"7"9"9"&,,..(/(9%)/)K)P)P/!( #u *Q * *& !,,=?Q R RI?H B B;(*;, @#3 e393T3T\c3T3d3d 09J9T,67H7P,4@Q@b,==- @;?,8+6 B,11D1AAAB ''666,3,= > >(7;(4(---====55777**,,,t,,,$$T**** 055=1!4D!4!4!45&&&>5  H
 $ + +T****+ 	'###		D	!!!!!s   !-CC	!C	c                     d| _         dS )u   
        Помечает, что календарь необходимо пересчитать и сбрасывает кэш дней
        TN)r  r   s    r+   r  zCmfCalendar._set_as_dirty  s     


r-   c                    | j         j        sdS | j         st          dd           n<| j        r5t	          | j        j        t          j                  rt          dd           d| j         d}t          j	        
                    dd	| j        gg d
gdg          }|r*d|_         |                    d           d|j         d| }t          |           dS )uX   
        Изменяет флаг "Календарь по умолчанию"
        Nu   Для сброса флага "Календарь по умолчанию" вы должны установить его у любого другого календаря.Tr_   u   Личным календарям пользователей нельзя устанавливать флаг "Календарь по умолчанию".uf   Во всех новых проектах будет использоваться календарь ""r   r   )
is_defaultr   Tr  r   Fr   u^   Сбросили флаг "Календарь по умолчанию" у календаря "z". )r  r   rd   r~   r   rt   rh   	CmfPersonr   r   r   r   r   )r   msgcurrent_default_calendars      r+   _set_is_defaultzCmfCalendar._set_is_default  sd    ) 	F 	E z BFG G G G G { Ez$+*;V=MNN E  x  @D  E  E  E  E Dw{  xA  D  D  D#)#5#9#9tTW%))) !> $: $
 $
  $ 	W27$/$))D)999V.F.KV VPSV VC#r-   c                 |    | j         j        rd| _         | j        j        rd| _        | j        j        r	d| _        dS dS )u}   
        Исправляет нулевые значения, если приходит null выставляет 0
        r   N)r'  is_nullr  r  r  s    r+   fix_null_valuezCmfCalendar.fix_null_value  sT     =  	DM& 	$"#D#+ 	)'(D$$$	) 	)r-   c                 N    t                                                      g dz   S )N)r'  r  r  )supersave_preload_fields)r   	__class__s    r+   r  zCmfCalendar.save_preload_fields  s%    ww**,,/d/d/dddr-   c                    | j         r}t          | dd           rt          j                            | j        g d          }|j        | _        |j        | _        |j        | _        |j	        D ]}|
                                }| |_        d|_        |                    d           |                    dg           |j        D ]3}|
                                }||_        |                    d           4|j        s|j        s|| _        |j        D ]}|
                                }	| |	_        |	                    d           |                    dg           |j        D ]3}|
                                }|	|_        |                    d           4nt(          j                                                                        j        }
t1          t(          j                            |
                                                                                    | _        t                              | d	          }t9          d
          D ]}t;          |d| dd           |                    d           || _        |                                  |                                  t1          | j                  dk    rtA          dd           t1          | j                  dk     rtA          dd           t1          | j                  dk    rtA          dd           t1          | j                  dk     rtA          dd           | j        j!        s| j        j!        r| "                                 | j#        j!        r0| j#        | k    rtA          dd           | $                                  tK                      j        |i |S )Ntemplate)r   zworkweeks.*zexclusions.*)r   r   FTr   r   u   По умолчаниюr~   r   r   r3   r   weekend   u\   Количество лет расчета не должно быть больше 30 летr_   r   u]   Количество лет расчета не должно быть меньше 1 годаr   un   Количество лет расчета в прошлое не должно быть больше 10 летr   uf   Количество лет расчета в прошлое не должно быть меньше 0ua   Календарь не может быть родительским для самого себя)&is_newrr   rh   r   r   r  r'  r  r  r   cloner~   systemr   r   r   rs   ru   r   r   r(   r   
astimezoner&  r&   	utcoffsetri   r   r%   r   r  r  rd   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.save!  sS   ; /	1tZ.. .1$*$6$:$:}??? %; % %! !2 :&7&F#+<+P():)D = =%#4#:#:#<#<L*.L'*/L' %%%555%11=/BBB->-H : :)'8'>'>'@'@.:+$))D)9999'9 =,B^ =0<-*;*F 	: 	:&$6$<$<$>$>M+/M(!&&&666&22M?CCC-?-I : :)'8'>'>'@'@.;+$))D)9999:	: &**,,7799@ #H$5$9$9"$=$=$G$G$I$I$W$W$Y$Y Z Z "55THa5bbq A AAHnAnnni@@@@---(0%t"##b((t  }A  B  B  B  Bt"##a''u  ~B  C  C  C  Ct'((2--  G  OS  T  T  T  Tt'((1,,~  GK  L  L  L  L) 	!T-E-P 	!   * 	##t++}  FJ  K  K  K  K  """uww|T,V,,,r-   c              #     K   d }dd}|                      dg           d}|}t          g           }d }	d}
d}	 |s0| j        rdd|gdd	|t          j        d
          z   gg} || j        |d          } || |d          }||z   }|r~i }|D ] }|j        | k    s	|j        |vr
|||j        <   !t          |                                          D ]7}||         }|j	        dk    s|r |j        ||fv r|
                    |           8nbddd|gg dgg}|r6|
s|
                    dd|g           |r|s|
                    dd|g           |                     || |                     |sO| j                                        }d }|sd| j         d}n$d| j         d| j                                         }|S |                                }|j        |k    r0|j	        dk    r# ||          }|j        |_        |j        |_        d}
|j        |k    rK|j	        dk    r>|	r|	j        |_        |	j        |_        n# ||          }|j        |_        |j        |_        d}|j	        dk    r|}	|V  t$                              |j        j        t$          j                                                  t          j        d          z                                   }|dz  })Nc                 z    t          t          |                     D ]}| |         j        dk    r
| |         c S d S )Nr   )r%   r9  r   )bufferr*   s     r+   _get_next_work_dayz1CmfCalendar.work_days.<locals>._get_next_work_dayl  sP    3v;;'' % %!9%//!!9$$$ 0% %r-   Tc                 t    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      rQ  r5   )r   rh   r   r   )rB   date_filterdo_slicer  s       r+   _get_calendar_daysz1CmfCalendar.work_days.<locals>._get_calendar_daysq  sd    !42K@iii   F
  *#$b'w(-77777r-   r  r   Fr.   r   <r  rK   )r  r   r   )r   r   r   r   u   Календарь "u   " не рассчитан.u   " рассчитан до r   )T)r   r   r  r(   r)   r~   r.   r   keysr   rL   r   r  loadr   popleftr   r   Datetimerb   rt   r   rc   )r   rF   r*  finish_dater  r  n	next_dater  prev_work_daystart_date_givenfinish_date_givenr  parent_days	self_daysr'   days_by_dater3   date_keyday_candidater  messagework_daynext_work_days                           r+   	work_dayszCmfCalendar.work_daysj  s     	% 	% 	%
	8 	8 	8 	8 	+,---	r !C	 I' I$*D)#<vsIX`XjprXsXsXsLs>t"uK"4"4T5I;af"g"g"gK 2 24u U U UI&2D =')#' = =C"zT11SX\5Q5Q9<SX 6(.|/@/@/B/B(C(C = =H,8,BM - 6& @ @$6 !A;H;MR\^iQj;j;j &m < < <#'64*CE_E_E_)`"aK) L/ K'..j/IJJJ& L/@ L'..k/JKKKMM"4"4T;"G"GHHH !_1133
! sZTYZZZGGrTYrrZ^ZiZnZnZpZprrG~~''H}
**$..$6$6v$>$>M-:-HH*6C6ZH3#' }++$..$ _1>1L.:G:^77(:(:6(B(B1>1L.:G:^7$(! F** (NNN!))(-*=x|?P?P?R?RSSV^VhnoVpVpVppvvxxIFAGC	r-   c                    |                      dg           | j        rt          dd           t          j                            | dg          }|r3d                    d |D                       }t          d	| d           |                    d
d          s7t          j        	                    |           }|rt          d| dd           t          j
                            | ddg          }|r3d                    d |D                       }t          d| d            t                      j        |i |S )Nr  u   Нельзя удалить календарь по умолчанию. Сначала назначьте любой другой календарь, как календарь по умолчанию.Tr_   r   )rB   r   z, c                 $    g | ]}d |j          d S )r  )r   )r7   projects     r+   r9   z&CmfCalendar.delete.<locals>.<listcomp>  s&    %R%R%Rg&9',&9&9&9%R%R%Rr-   uk   Невозможно удалить календарь, он используется в проектах: from_person_deleteF)rB   uY   Невозможно удалить календарь, он используется у u    пользователейzparent.namec                 >    g | ]}d |j         j         d|j         d S )r  z: r  )r7   slas     r+   r9   z&CmfCalendar.delete.<locals>.<listcomp>  s2    &_&_&_c'I3:?'I'Ich'I'I'I&_&_&_r-   ue   Невозможно удалить календарь, он используется в целях: )r   r  rd   rh   
CmfProjectr   joinr   r  countCmfSDeskSlaGoalr  r  )	r   r  r  projectsprojects_strperson_count	sla_goalssla_goals_strr  s	           r+   r  zCmfCalendar.delete  s   ,(((? 	" Z " " " " $))4)II 	"99%R%R%R%R%RSSL  S  EQ  S  S " " " "zz.66 	&!+1141@@L &  `  wC  `  `  ` $& & & & *//v}F]/^^	 	" II&_&_U^&_&_&_``M  N  L  N  N " " " " uww~t.v...r-   )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&   rE   r   rN   rR   rU   rX   Timer	   r  re   rj   classmethodr|   r   r   r   boolr   r   r   r
   rx  cmfr   CmfTyper   r   on_server_eventr   r   r   r   r   r   r  r   r  r  r6  r;  rA  cmf_deferred_jobrV  r    r  r  r  r  r   r  r  __classcell__)r  s   @r+   r   r      sM       +8<GL*6:
 
K
 5 5 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 1c 11031!17:1FJ4j1 1 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4 44 44l N= N N N N N [N` FJ04, ,= ,(,,?C,)-,9A, , , [,. j$LMMG/uS-9K%KL /TX /]d / / / [/ . . \.
 _233: : 43 \:
 YtL Lc L Lhsm LW^ L L L  \L> >BS  S ] S !#sD(":;S GOS  S  S  [S j:" :"# :"T :"h :" :" :" :"x( 8      05D DM DH DU] D:=D D D [DL @A2 2M 2&.2:=2FN2 2 2 [2h & & \&P 7 7 \7r VXYYY  ZY \:p" p" p"d    :) ) )e e e e eG- G- G- G- G-R] ] ]~/ / / / / / / / /r-   r   )rB   r;   r(   rc   	functoolsr   collectionsr   r   typingr   r   r   r	   r
   r   r   pytzcmf.includecommon.fieldsr   dateutil.relativedeltar   r   r  r  r.   r  r  r   r5   r-   r+   <module>r     sH               ) ) ) ) ) ) ) ) C C C C C C C C C C C C C C C C 



      & & & & & & 4 4 4 4 4 4 4 4 HHHhH	  }}G/ G/ G/ G/ G/,* G/ G/ G/ G/ G/r-   