U
    1e2                     @   s   d dl Zd dlZd dlmZ d dlmZmZmZm	Z	m
Z
 d dlZd dlT d dlmZ d dlmZmZ ejZejZejZG dd dejZejej dS )	    N)	lru_cache)IteratorListNoReturnTupleUnion)*)cmf_calendar)MOrelativedeltac                       sX  e Zd Zeeeee dddZedJeeeeedddZedKeeeee	e d	d
dZ
edLeeeee	e e	e dddZedMeeeeeeee	e dddZedNeeeeeeee	e dddZedOeeeeef dddZedPeeedddZedeee	e f dddZed eeddd ZedQd eeeed"d#d$ZeedReed ejjf eeed&d'd(Z edSd eeeeef ed)d*d+Z!dTd,d-Z"ed eeed.d/d0Z#edUd eeed2d3d4Z$d5d6 Z%d7d8 Z&d9d: Z'd;d< Z(d=d> Z)d?d@ Z*dAdB Z+ee,j-d!d!dCdDdE Z.edFdG Z/ fdHdIZ0  Z1S )VCmfCalendar)
date_startdate_endreturnc                 c   s0   t t||  jd D ]}| t| V  qdS )u   
        Генератор диапазона дат

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

        Yields:
            Iterator[Date]: дата
           N)rangeintdaysdatetime	timedelta)r   r   i r   ./common/models/cmf_calendar.py_date_range   s    zCmfCalendar._date_rangeN)date	month_daypositionday_of_weekr   c           	         sz   |r2t  j jd }||k r$|} j|d}nDt  }| j j} fdd|D }|dk rn|| 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                    s$   g | ]}| j  j kr| qS r   )month).0Zweekr   r   r   r   
<listcomp>:   s      z=CmfCalendar._get_day_by_position_in_month.<locals>.<listcomp>   )clZ
monthrangeyearr    replaceZCalendarZmonthdatescalendar)	r   r   r   r   Zdays_in_monthr   calendarweeksZday_of_weeksr   r"   r   _get_day_by_position_in_month    s    z)CmfCalendar._get_day_by_position_in_monthr   )
start_dateend_daterepeatsperiodr   c                 C   sR   g }|dk	rd}| }|rN|dkr*|d8 }n
||kr4qN| | |t|d7 }q|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   )r,   r-   r.   r/   r   current_dater   r   r   	every_day?   s    

zCmfCalendar.every_day)r,   r-   r.   r/   weekdaysr   c           	      C   s   g }|dk	rd}| t tdd }|r|D ]N}|t |d }|| krp|dkrV|d8 }n||krfd} qz|| |s* qzq*|t |d7 }q"|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)r*   )r   r
   r1   )	r,   r-   r.   r/   r4   r   r2   r6   r   r   r   r   
every_weeka   s$    

zCmfCalendar.every_week)r,   r-   r.   r/   r   r   r   r   c                 C   s   g }|dk	rd}| }|rt j||||d}	|	| krX|dkrD|d8 }n
|	|krNq||	 |jd | }
|j|
d  }|
d d }
|j||
d}q|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   r   r   r      )r'   r    )r   r+   r1   r    r'   r(   )r,   r-   r.   r/   r   r   r   r   r2   r   r    r'   r   r   r   every_month   s(     

zCmfCalendar.every_month)r,   r-   r.   r    r   r   r   r   c           
      C   sz   g }|dk	rd}| j |dd}|rvtj||||d}	|	| krb|dkrN|d8 }n
|	|krXqv||	 |j |jd d}q|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   r    r   r8   )r'   )r(   r   r+   r1   r'   )
r,   r-   r.   r    r   r   r   r   r2   r   r   r   r   
every_year   s"     

zCmfCalendar.every_year)	from_timeto_timer   c                 C   sf   t j }t j || } t j ||}t dd| krJ|t jdd7 }| |kr^td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      )Zhoursuo   Время начала должно быть раньше времени окончания интервалаTabort)r   r   todaycombinetimer   	cmf_alert)r=   r>   rB   r   r   r   normalize_time_interval   s    
z#CmfCalendar.normalize_time_intervalc                 C   s.   | r|sdS t j| |\} }||   d S )u?  
        Вычисляет в минутах интервал времени

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

        Returns:
            int: минуты
        r   <   )modelsr   rF   total_seconds)r=   r>   r   r   r   get_interval_minutes  s    z CmfCalendar.get_interval_minuteszmodels.CmfCalendarExclude)	exclusionr   c           	         sb  g }d} j j} jj} j} j} jdkrN jdkrNd}| |||}n jdkrvd}| j||| j j	d}n jdkrd	}| j||| j j
 jd
}n jdkrd}| j|||| j	d}n jdkrd}| j|||| j
 jd}nh jdkr.d} fddtdD }| j|||||d}n, jdkrZ jdkrZd}| ||||}||fS )uw  
        Расчитывает и возвращает исключительные дни и приоритет исключения
        Приоритеты исключений (7-самый высокий, 1-самый низкий):
            7 - Ежедневно (каждый день)
            6 - Ежегодно (в указанный день)
            5 - Ежегодно (по позиции дня недели месяца)
            4 - Ежемесячно (в указанный день)
            3 - Ежемесячно (по позиции дня недели)
            2 - Еженедельно
            1 - Ежедневно (каждый N день)

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

        Returns:
            Tuple[int, List[Date]]: приоритет, список дат
        Nr3   r      Zevery_year_day   )r    r   Zevery_year_week_day   )r    r   r   Zevery_month_dayr$   )r   Zevery_month_week_day   )r   r   r7      c                    s"   g | ]}t  d | dr|qS )r   F)getattr)r!   r   rK   r   r   r#   X  s      z2CmfCalendar.calc_excluded_days.<locals>.<listcomp>)r4   )period_start_datevalueperiod_end_dater/   Zrepeat_timesrepeat_typer3   r<   r    r   Zmonth_week_positionZmonth_day_weekr:   r   r7   )	clsrK   r   priorityr,   r-   r/   r.   r4   r   rR   r   calc_excluded_days  sT    

 



 
zCmfCalendar.calc_excluded_days)r)   r   r   c                    s  d}g }|   d  }tjj|ddgdddgdd|gd	d
|ggd}d}|D ]4}| |\}	}
|	dkrlqP||
krP|	|krP|	}|}qP|r|jj}|jj}|dkr|dd |j	D  ntj
j|ddgdd|gd	d
|ggd}|rt|| djdkr|ddg |j}t|| dj}t|| dj}|dkrX| fdd|j	D  tjj||d}|stj||d} |_|j|_|j|_|j|_||_||_||_|  |S )u   
        Пересчет указанного дня календаря

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

        Returns:
            NoReturn
        Nr   r   intervals.*rV   !=rS   <=rU   >=parentfieldsfilterr   workc                 s   s*   | ]"}|j jd |jjd gV  qdS %H:%MNr=   rT   strftimer>   r!   intervalr   r   r   	<genexpr>  s   z*CmfCalendar.recalc_date.<locals>.<genexpr>_typedefaultdefault_workweek.*default_workweek.intervals.*_intervals_total_minutesc                 3   s6   | ].}|j j kr|jjd |jjd gV  qdS rc   day_weekrT   r=   rf   r>   rg   r5   r   r   ri     s    r_   r   )r6   rH   CmfCalendarExcludelistrY   exclude_typerT   intervals_total_minutesextend	intervalsCmfCalendarWorkWeekgetrQ   load_fieldsdefault_workweekCmfCalendarDayrp   r'   r    r   day_typeinterval_total_minutesinterval_jsonsave)rW   r)   r   r   rw   day_num
exclusionsZexclusion_priorityrK   rX   Zexcluded_daysr}   r~   calendar_dayr   r5   r   recalc_datea  sj    




zCmfCalendar.recalc_dateT)r)   r   r   back_recalcr   c                 C   sh   |dkr$t j   }|jddd}|dkrF|tdd t jdd }| ||D ]}| || qRdS )u$  
        Пересчет дней календаря
        Если интервал не задан, делает пересчет от начала текущего года +2 года, итого 3 года

        Args:
            calendar (CmfCalendar): объект календаря
            date_start (Date, optional): начальная дата
            date_end (Date, optional): конечная дата
            back_recalc (bool, optional): пересчет назад только текущего года
        Nr   r;   rO   )Zyearsr0   )r   rB   r   r(   r   r   r   r   )rW   r)   r   r   r   rB   r   r   r   r   recalc_calendar_day  s    zCmfCalendar.recalc_calendar_dayF)r)   r   detailr   c                 C   s   t |d}tjjdd|gdd|ggdddgd}t j|d	gd
}|sdtd|dd|j ddd |jr|td|j d |j	j
|jj
|jj
i dS )u<  
        Получает день календаря

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

        Returns:
            day (dict): информация о дне календаря
        r   Z	parent_id=r   r}   r~   r   ra   r`   dirtyr`   u	   День z%d.%m.%Yu*    не найден в календаре "uO   ". Попробуйте запустить пересчет календаря.Tr@   u   Календарь "u   " не пересчитан, это может привести к некорректному вычислению дат или длительности. Запустите пересчет календаря в настройках.)typerw   ru   r   )ZcmfutilZget_obj_id_by_anyrH   r|   ry   Zget_obj_by_idrE   namer   r}   rT   r   r~   )rW   r)   r   r   Zcalendar_idr   r   r   r   get_day  s"    zCmfCalendar.get_day)r)   r'   r   c                    s  |dkrt j  j}nt|t js.t|t j r4|j}t t|dd}t t|dd}t }|}||kr| |j|j|j	ddg d||< |t j
dd7 }qb|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d}| D ]r\}	}
|	 d }t|| dj}t|| dj}||
d< ||
d< |dkrfdd|jD |
d< q|D ]}|jj}||jkrd}g }| d }t|| dj}|dkr|t j
dd7 }q|dkrt|| dj}fdd|jD }||}|r:||d< ||d< ||d< |t j
dd7 }qqtjj|d
dgd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gd} fdd|D }t|D ]r\}}}d}g }|jj}|dkr |jj}d d |jD }|D ].}	||	}|r||d< ||d< ||d< qqtjj||d
gd!}|D ]P}||jjd}
|
rP|
 D ]\}}t||| qr|jrP|jd"d# qP| D ]@\}	}
tj||	d$}|
 D ]\}}t||| q|  qdS )%uQ  
        Расчитывает все дни года с учетом рабочих недель и исключений и сохраняет их в БД

        Args:
            calendar (CmfCalendar): объект календаря
            year (Union[str, int, Date, Datetime], optional): год. Defaults to None.
        Nr   r9      r   )rp   r'   r    r   r}   r~   r   r0   rl   rm   r   rZ   ORrS   r]   r\   rU   r^   r   rj   rn   r}   r~   rb   c                    s4   g | ],}|j j kr|jjd |jjd gqS rd   ro   rg   r5   r   r   r#   (  s    z-CmfCalendar.calc_one_year.<locals>.<listcomp>r   rk   c                    s4   g | ],}|j j kr|jjd |jjd gqS r   ro   rg   r5   r   r   r#   >  s    rV   r[   c                    s   g | ]}  ||f qS r   )rY   )r!   rK   rW   r   r   r#   [  s     c                 S   s(   g | ] }|j jd |jjd gqS r   re   rg   r   r   r   r#   b  s   )r_   r'   r`   TZ	only_datarq   ) r   nowr'   
isinstancer   r   dictr6   r    r   r   rz   r{   rH   rx   rs   itemsrQ   rT   rw   rS   rU   ry   rr   sortedrt   ru   r|   popsetattr
is_changedr   )rW   r)   r'   Zstart_date_yearZend_date_yearZdays_of_yearr2   r{   Z	workweeksr   Zday_datar   r}   r~   workweekZcurrent_period_daterw   Zday_of_yearr   Zexcluded_dates_ZdatesrK   Zcalendar_daysr   Z
field_namerT   r   )rW   r6   r   calc_one_year  s    

	









zCmfCalendar.calc_one_yearc                 C   s   |  ddg | js|sdS tj j}|t| j }t||D ]&}tj	
| | tt|dd| _q@tj	j  d| _| jdd dS )	u   
        Пересчитывает дни календаря

        Args:
            force (bool, optional): принудительный пересчет дней календаря. Defaults to False.
        r   calc_num_yearsNr9   r   FTr   )rz   r   r   r   r'   r   r   r   rH   r   r   r   Z
calc_untilr   cache_clearr   )selfforceZ	from_yearZto_yearr'   r   r   r   recalc_calendar  s    
zCmfCalendar.recalc_calendar)r)   from_dtto_dtr   c                 C   s  dd }d}t t jt|jpdd}| }| }||kr| ||}	|	d dkrl|t jdd7 }q8|	d	 D ]}
t j |
d d
 }t j |
d d
 }t j j|||d}t j j|||d}| t ddkr|t jdd7 }|||||}||7 }qt|t jdd7 }q8|S )u  
        Получает продолжительность рабочего времени в минутах из указанного диапазона дат

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

        Returns:
            minutes_sum (int): сумма минут
        c                 S   s8   t | |}t||}||k r0t||  d S dS d S )NrG   r   )maxminr   rI   )r   r   interval_startinterval_endstartendr   r   r   	intersect  s
    

z3CmfCalendar.get_duration_minutes.<locals>.intersectr   Zsecondsr   rb   r   r0   rw   rd   tzinfo)	r   timezoner   r   r   r   strptimerD   rC   )rW   r)   r   r   r   Zminutes_sumtzr2   r-   r   rh   r=   r>   r   r   Zinterr   r   r   get_duration_minutes  s*    	

z CmfCalendar.get_duration_minutesr   )r)   r   durationr   c                 C   s  |s|S t t jt|jpdd}d}|dk r<d}t|}| }|dkrl| ||}|sf|d ntt|d }|D ]}	t j 	|	d d
 }
t j 	|	d d
 }t j j||
|d}t j j|||d}|
 t 
ddkr|t jdd	7 }|st||n|}|rt||n|}|||k r:t||  d
 nd8 }|dkrz qPqz|t j|s`dndd	7 }qD|r|t jt|d }n|t jt|d }|S )u$  
        Рассчитывает дату и время на основе длительности от указанной даты и времени

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

        Returns:
            to_dt (Datetime): рассчитанная дата и время
        r   r   FTrw   rd   r   r   r0   rG   r%   )Zminutes)r   r   r   r   absr   r   rs   reversedr   rD   rC   r   r   rI   )rW   r)   r   r   r   reverser2   r   rw   rh   r=   r>   r   r   r   r   r   r   r   r   get_date_by_duration  s8    
&z CmfCalendar.get_date_by_durationc                    s   t t fdd| jj}|S )Nc                    s   | j t  kS N)rp   strr6   )xr   r   r   <lambda>      z*CmfCalendar.get_schedule.<locals>.<lambda>)rs   ra   r{   rw   )r   r   scheduler   r   r   get_schedule  s    zCmfCalendar.get_schedulec                 C   s   | j r
dS dS )NTF)r   )r   r   r   r   r   is_exclude_day  s    zCmfCalendar.is_exclude_dayc                 C   s.   | j r*t| j d|  d}|dkr*dS dS )Nr   rj   weekendTF)r{   rQ   r6   )r   r   r}   r   r   r   is_weekend_day  s
    zCmfCalendar.is_weekend_dayc           	      C   s   t j   j}| |}t ddd}t d}|D ],}||jjkrN|jj}||jjk r6|jj}q6t j j	|||d}t j j	|||d}||fS )N   ;   r   r   )
r   r   Z
astimezoner   r   rD   r=   rT   r>   rC   )	r   r2   r   r   Z_minZ_maxitemworkday_start_timeworkday_end_timer   r   r   set_worktime_border  s    


zCmfCalendar.set_worktime_borderc                 C   s  |  ddddddg |}d}| js(|S ||kr|jdddd}| |rX| |sR| |\}}||  krz|krn n||  kr|krn nq| | kr| | kr||kr||kr|t||  d	 t||  d	  7 }n||kr*||kr*|t||  d	 7 }n||krX||krX|t||  d	 7 }nj||  krp|krn n|t||  d	 7 }n4||  kr|krPn n|t||  d	 7 }q| | kr
| | kr
|d
t||  d	  7 }q| | kr||  kr4|krRn n|t||  d	 7 }nN||krv|t||  d	 7 }n*||krP|t|| ||   d	 7 }n| | kr||  kr|krn n|d
t||  d	  7 }nb||kr*|d
t||  d	  t||  d	  7 }n&||kr|d
t||  d	  7 }nH| | kr|d
t||  d	  7 }n|t||  d	 7 }|t	j
dd7 }|jdddd}q(|S )u~   
        Вычисляет величину паузы попадающее в нерабочие интервалы
        r{   default_workweek.intervals#default_workweek.intervals.day_weekr   $default_workweek.intervals.from_time"default_workweek.intervals.to_timer   )ZhourZminutesecondrG   i  r   r0   )rz   r{   r(   r   r   r   r   r   rI   r   r   )r   r   stopr2   Znon_working_timeZ	begin_dayr   r   r   r   r   calc_non_working_pause_duration+  sx     
 
$
$ 




z+CmfCalendar.calc_non_working_pause_durationc                 C   s  |  ddddddg | js0t||  d S |}d}||kr| |rX| |s| |\}}||  krz|krn n4||  kr|krn n|t||  d 7 }qt||  d dkr4t||  d dk rnLt||  d dkr|t||  d 7 }n|t||  d 7 }nLt||  d dkrh|t||  d 7 }n|t||  d 7 }|tjd	d
7 }q8|S )u   
        Вычисляет величину паузы попадающее в рабочие интервалы
        чтобы правильно скорректировать elapsed_time
        r{   r   r   r   r   r   rG   r   r   r0   )	rz   r{   r   rI   r   r   r   r   r   )r   pause_interval_start_timepause_interval_stop_timer2   pauser   r   r   r   r   calc_work_pause_duration  s@    	 
 
z$CmfCalendar.calc_work_pause_durationc              	   C   s^   t jjdddgdddgdddgdd| ggddd	d
dddgd}|D ]}|j  |  qBdS )u   
        Обработчик смотрит только активные циклы (не на триггерной паузе и не фуллтайм)

        Zbreachedr   FalseZpausedZ	stop_timeZNULLzsla_goal.calendarZsla_goalcodeZwithin_calendar_hoursr   r   last_time_updater   N)rH   ZCmfSDeskSlaCyclers   r   Zset_nowr   )r   Zcyclescycler   r   r   calendar_handler  s    
 
zCmfCalendar.calendar_handler)Z	only_onceZsystem_taskc                  O   s2   t jjddddddgd}|D ]}t| qd S )Nr{   r   r   r   r   r   r   )rH   r   rs   r   )_args_kwargsZ	calendarsr)   r   r   r   celery_hourly_hook  s    zCmfCalendar.celery_hourly_hookc                 C   s   t | j d S r   )Zcmf_deferred_taskr   r   r   r   r   hourly_hook  s    zCmfCalendar.hourly_hookc                    s   | j rHtj| dd}tdD ]}t|d| dd q|jdd || _t| jd	krbt	d
dd | jj
rpd| _| jj
rtjj  t j||S )Nu   По умолчанию)r_   r   rL   r   rj   r   Tr   
   u\   Количество лет расчета не должно быть больше 10 летr@   )Zis_newrH   rx   r   r   r   r{   r   r   rE   r   r   r   r   r   super)r   argskwargsr   r   	__class__r   r   r     s    zCmfCalendar.save)NNN)NNr   )NNr   N)NNr   NNN)NNNNNN)NN)NN)NNT)F)N)F)r   )2__name__
__module____qualname__staticmethodDater   r   r   r+   r   r3   r7   r:   r<   Timer   DatetimerF   rJ   classmethodrY   r   r   boolr   r   r   r   Zcmfr`   ZCmfTyper   r   r   r   r   r   r   r   r   r   r   r   r   Z
celery_appZtaskr   r   r   __classcell__r   r   r   r   r      s            !  
 *          3          /   
AM         &   
7   4T3-
r   )r)   r&   r   	functoolsr   typingr   r   r   r   r   ZpytzZcmf.includeZcommon.fieldsr	   Zdateutil.relativedeltar
   r   rD   r   r   r   r   r   ZAPPZHOOK_CRON_HOURLYr1   r   r   r   r   r   <module>   s(           