B
    f                 @   s^   d dl m Z mZmZ d dlmZ d dlmZ d dlT d dlm	Z	m
Z
mZ G dd de	jZdS )	    )datetime	timedeltatimezone)uuid1)	dataclass)*)
cmf_notifyCmfRelationCmfTypec                   s  e Zd ZdZdZdZi Zee	j
ejde	j
ejdgZeed< ejf eZejjddg ZeG d	d
 d
Zedd Zedd Zedd Zed;ddZedd ZeedddZeedddZed<ddZed d d!edd"d#Z  fd$d%Z!ed=d&d'Z"ed>d(d)Z#ed*d+ Z$e%e&d d d,d-d. Z'e%e&d d d,d/d0 Z(ed1d2 Z)ed3d4 Z*ed5d6 Z+e%e&d d d7d8d9d: Z,  Z-S )?	CmfNotifyZNotifyZdeskZNTFzcommon/templateszcmf/templatesloaderclose_open_notifiesconfirm_unconfirmed_notifiesc               @   s*  e Zd ZU dZdZeed< dZeed< dZeed< dZ	e
ed< dZeed	< dZeed
< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZeed< dZ dS )zCmfNotify.NotifyCtxu1  
        notify_type - тип сообщения
        возможные варианты:
        - просто сообщение (default) -- message
        - редактирование объекта -- obj_edit
        - создание объекта -- obj_create
        - удаление объекта -- obj_delete
        - добавление комментария -- comment_create
        - редактирование комментария -- comment_edit
        - удаление комментария -- comment_delete
        N	person_idnametextr   priorityFstrikethrough
alarm_datemessagenotify_typeobj_hrefobj_codeobj_parent_nameobj_link html_changed_fields
owner_nameowner_initialsperson_phone_mobileperson_phoneperson_nameperson_emailperson_loginmsg_from_idmsg_from_namemsg_from_codemsg_from_login)!__name__
__module____qualname____doc__r   str__annotations__r   r   r   intr   boolr   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   comments r1   r1   ./cmf/models/cmf_notify.py	NotifyCtx   s2   
r3   c             C   sl   |j p
|j}d|j d|j d|j }|  }|r<| }| j|}|j|d}t	| j
|||gd d S )N[z] (z) )ctx)args)r"   r#   r   r   r   +get_default_mail_notification_template_name
_jinja_envget_templaterenderschedule_deferred_jobprocess_email)cls
notify_ctxobjrcpt_tosubjectmail_templatetemplate
email_bodyr1   r1   r2   send_email_notify_old?   s    zCmfNotify.send_email_notify_oldc             C   s   t dd}|jp|j}t|dkr4|d d  d}| d|j d| |j }|jpZ|j}|svtd|j d d S t	| j
||gd d S )	NT)full_url   z...
u4   SMS уведомление пользователю u_    не отправлено, не указан номер мобильного телефона.)r6   )app_base_hrefr   msglenr   r   r    	cmf_alertr!   r;   process_sms)r=   r>   urlsubjr   phoner1   r1   r2   send_sms_notify_oldN   s    
zCmfNotify.send_sms_notify_oldc       	      K   s  d|ks|d dkr&t jtjd|d< d|kr:|d}ntj}|jj|d< |j	j|d< |j
j|d< |jj|d< d	|d
< |rd|ks|d dkr|j	|d< d|ks|d dkrt jtjd|d< t|d tr|d j|d< |d |d< |ptj}|j	j|d< |ddg |jr |jjd nd|jr6|jjd nd |d< |rtdd}|j|d< |j
|d< | |d  |d< t|dr|jr|jj	j|d< nd |d< tj|}||d< |d |d< |d |d< |d
 |d < |d! |d"< |d# |d$< | jf |}|S )%Nr   .)tzmsg_fromr$   r%   r&   r'   u   Уведомлениеr   r   rJ   r   r   
first_name	last_namer   r   r   T)rF   r   r   r   parentr   r   rP   r    phone_mobiler   r!   emailr"   loginr#   )r   nowr   utcpopgcurrent_personidvaluer   coderY   
isinstancer
   current_userload_fieldsrT   rU   rI   hrefhasattrrV   models	CmfPersonget_notify_opt_cachedr3   )	r=   r?   r   kwargsrS   Znotify_ownerrN   notify_optsr5   r1   r1   r2   prepare_notify_ctx_old\   sL    

4


z CmfNotify.prepare_notify_ctx_oldNr   Fr   c
          	   K   s  t jrt d dS t|d}tj|}|dkr8dS d}|t jj	krb|dkrb|d r^d}ndS |r|j
jrv|jjs|ddg d}|rd	}|sd
}| jdd|j	gdd|gdd|gdddgdddggdddgd}|st }|sd}|jr|jdkr| d|j }|jr$|jr$|r*||_d	|_| jd7  _||_||_d|_|	r^|	|_n
|j  |r|j|_|j	|_|j|_|j|_t|dr|j
r|j
jj|_ |j!|_"t|dr|j# rt$|jt%r|jj|_&nt'|j|_&nd|_|j(s
g |_(|j(rFt)|j(jdkrF|j(jdd d d |krF|S t j*j+r^t j*j+jd ndt j*j,rxt j*j,jd nd }|r|jjnd}t j*j	jt j*jjt j*jjt j*j-j|dt.j/t0j1d2 t./ 3d||dt4  |dd }|j(5| d|_6|jp||_|d! |_7|d" |_8|d# p.|d$ |_9|d% pB|d& |_:|sRd
|_|;  |d' sp|j<d(krt=d)|||j"jd*|gd+ |j<d,kr|j>st=d-| |gd+ |S ).u  
        obj: CmfEntity

        :param obj:
        :param msg_from:
        :param person: Идентификатор пользователя которому отправляется сообщение
        :param name: Наименование объекта уведомления
        :param msg: Текст сообщения
        force - форсированная отправка
        :param priority:
        :param strikethrough:
        :param alarm_date: Будильник для уведомлений
        :param force_notify_current_person: отправить сообщение себе
        :param notify_type: Тип сообщения. Описание см в структуре NotifyCtx
        uB   Уведомления отключены g.disable_notify = FalseNrh   TFemail_if_self_changesrV   ra   openclosedobj_idz==r   status	cron_done	confirmed
unread_cntr0   
cron_force)filterfieldsu   Уведомлениеr   u
    + еще    r   r   )r_   r   ra   rY   Zinitials)rR   z%H:%MzCmfComment:)Z	cmf_ownerZcmf_created_atZcmf_created_at_formattedmsg_type_textr   r_   parent_name	log_level
notify_smsZnotify_emailrW   rP   rX   rY   Z	notify_os1z	notify-os)r   commentr   )event_persons2znotify-important-)?r]   disable_notifydebugcmfutilZget_obj_id_by_anyrg   rh   ri   r^   r_   rV   
is_definedra   rd   getr   rt   r   ru   rq   Zpriotityr   r   r   Zset_nowr   rp   r   ui_nameZobj_ui_namerf   r`   r   re   r   loadrb   r	   Zobj_status_namer,   r0   rK   rc   rT   rU   rY   r   rZ   r   r[   Z	isoformatZstrftimer   appendrr   person_notify_smsperson_notify_emailr    r"   saver   cmf_emit_eventrs   )r=   rJ   personr   rz   r?   force_notify_current_personforcer   r   rj   r   rk   Zdesk_notifynotifyZfilter_statusr   r{   r   r1   r1   r2   place_notify   s    








zCmfNotify.place_notifyc       	      K   s0  t jrt d dS d|kr(|d dk	s0tdd|krD|d dk	sLtd|d t jjkrj|dsjdS d	|kr|d	}|d
dddg nd}|d}t	j
j|dddgd}|st d|  dS |dg }t	j||}| j||f|}|dkrdS | ||}|r,| || | | |S )u  
        obj: CmfEntity

        :param obj:
        :param msg_from:
        :param person_id: Идентификатор пользователя которому отправляется сообщение
        :param recipient_opt: Опции получателя для проверки разрешения получать уведомления пользователем
        :param name: Наименование объекта уведомления
        :param text: Тема сообщения
        :param msg: Текст сообщения
        :param priority:
        :param strikethrough:
        :param alarm_date: Будильник для уведомлений
        :param force_notify_current_person: отправить сообщение себе
        :param notify_type: Тип сообщения. Описание см в структуре NotifyCtx
        uB   Уведомления отключены g.disable_notify = FalseNrJ   .u   Укажите msgr   u   Укажите person_idr   r?   rV   ra   r   re   r}   zphone_mobile.numberzphone.number)r_   rw   u   В метод place_notify пришел отсутствующий или удаленный пользователь person_id=recipient_opt)r]   r   r   AssertionErrorr^   r_   r   r\   rd   rg   rh   ZCmfPersonNotifyOptZcheck_permission_notify_eventZprepare_notify_ctxZcreate_desk_notifysend_email_notifysend_sms_notify)	r=   rj   r?   r   r   r   Znotify_allowedr>   r   r1   r1   r2   stol_place_notify;  s6    




zCmfNotify.stol_place_notify)event_type_codec             C   s  t  }t|drP|jdkrP|jr,|jdsPx| D ]}dh||jj< q6W |S |j}|jdkrh|jj}t|dsvd}tj	
||j d| }|stj	
|d| }|sdS g }xF|d D ]8}|j|d	d
}	|	dkr||t  || d qx|	D ]}
tj|
jj}|dkr"q |
js4||
 ||
jjt  d}|dkrd|d rdd	}nx|dkr~|d r~d	}n^|dkr|d rd	}nD|dkr|d rd	}n*|dkr|d rd	}||
jj d |r ||
jj d q W qW |rztjjdd}tjj|j|dgd}xP|D ]H}t|tjjrH|j}|jj|kr.|r.||d kr.||jj= q.W |d r>|jdkr>||d  x|d D ]}|| sqtt|| tjjrxd|| D ]*}||jjt  ||jj d qW n,||| jjt  ||| jj d qW xv|D ]n}|drftd| dd t j!rDtjj|d gd!}|rD|j"rD|j"jdrDtd"| dd qDW |S )#uY   
        Рассчитываем набор юзеров и их галочек
        logic_prefixZ
CmfProjectzCmfProject:rX   N.z
AllModels.Znotify_membersT)Zall_nested_personsFz
var:authorZemail_if_authorz	var:ownerZemail_if_owner)zvar:responsiblezvar:executorsZemail_if_responsiblezvar:spectatorsZemail_if_spectatorzvar:current_userrm   rc   zsdesk-client:default)ra   members)	parent_idZproject_role_idrw   Znotify_custom_fieldCmfTaskzvar:zDEV: Var user in notify! )abortra   )r_   rw   z DEV: Var user person in notify! )#dictrf   
class_namer   
startswithZall_relation_personsr_   r`   rg   ZCmfProjectNotifySchemeZget_notify_rule_data_cachedZextract_var_obj
setdefaultsetaddrh   ri   
user_localr   ZCmfProjectRoler   ZCmfProjectRoleAssignrV   rb   cmfrw   ZCmfRelationBaserd   
issubclasstypeZ
CmfM2MBaserL   configDEBUGra   )r=   r?   r   Z
recipientsuZtmp_parent_idZ	rule_dataZnon_local_personsZuser_idZ	var_usersZvar_userrk   rX   Z	proj_roleZproj_role_assignuser
field_nameir1   r1   r2   get_notify_memberst  s    







"

zCmfNotify.get_notify_membersc             C   s6  |dkrd}d}d||dgS |dkr<d}d}d||dgS |d	krZd
}d}d||dgS |dkrd}|d|j   7 }d}d||dgS |dkr|jdkr|jdkrd}d}nDd}|jj|jj }|d| 7 }|jj|jj }|d| 7 }d}d||dgS |dkrPd}|d|j j d|j jr4|j jnd 7 }d}d||dgS |dkr|jrd}|d|j   7 }d}d||dgS |d krd!}|d|j j d|j jr|j jnd 7 }d"}d||dgS |d#kr|jrd$}|d%|j	 7 }d&}d||dgS |d'kr>d(}|d%|j	 7 }d)}d||dgS |d*kr^d+}d,}d||dgS |d-kr|jrd.}d/}d||dgS |d0krd1}d2}d||dgS |d3krd4}|j
jr|d5|j
jj	 7 }|j
r|d6|j
j	 7 }d7}d||dgS |d8krg }|jjrd9}|jr*|jj	}d9}	|jr>|jj	}	d:| }||	kr`|d;|	 7 }|d<7 }|jj r|d%|jj  7 }d=}|d>||d |jjrt|jt|jj }
|
rd?d@dA |
D }d:| d<}|jj r|d%|jj  7 }dB}|d>||d |S |dCkr2dD}d>dE|dgS |dFkrhdG}|jj rVt|jj }dH}d>||dgS |dIkrdJ}|jj rt|jj }dK}d>||dgS |dLkrdM}|jj rt|jj }dN}d>||dgS |dOkr
dP}|jj rt|jj }dQ}d>||dgS |dRkr|jjr>|jr>|jjj|jjkr>g S |jdSkr\dH}d>dT|dgS d9}	|jrp|jj	}	dU|jj	 dV|	 d<}|jj r|d%|jj  7 }|jjr|jrdW|jjj	 dX|jj	 dY}ndZ}d>||dgS |d[kr
d\| }d]}d>||dgS |d^kr*d_}d`}d>||dgS |dakrRdb| dc}dd}d>||dgS |dekrrdf}dg}d>||dgS |dhkrdi}dj}x0|jjD ]$}||jjkr|dk|j	 7 }qW x0|jjD ]$}||jjkr|dl|j	 7 }qW d>||dgS dmdndodpdqg}|drkrg g g ds}xz|jdtduD ]j\}}|js<q(|j|jkrNq(||kr\q(||}|dvk rtq(| }|r(|| | q(W g }dw}|dv r|dvd|dv |d |d> r|d>d|d> |d |d r|dd|d |d |S | }d>dx| dy|j	 |dgS )zu  
        Логика:
        - по спец. событиям типа assigned, придет и assigned и updated, поэтому поля спец.событий
            дополнительно нужно отфильтровывать в updated
        Zrestoredu   Восстановленоu   восстановил   )r|   r   message_titleZdeletedu   Удаленоu   удалилZcreatedu   Созданоu   создалZ	publishedu9   Выпущены изменения в документеz<br>u!   выпустил документZshareddefaultu[   Отменен публичный доступ к документу в интернете.u9   отменил публикацию в интернетеui   Документ опубликован для публичного доступа в интернете.u   <br>Анонимные: u"   <br>Авторизованные: u,   опубликовал в интернетеZcomment_createdu$   Комментарий создан.z: r   u%   написал комментарийZcomment_updatedu&   Комментарий изменен.u%   изменил комментарийZcomment_deletedu#   Комментарий удаленu#   удалил комментарийZattachment_createdu#   Добавлено вложение u   добавил вложениеZattachment_deletedu   Удалено вложениеu   удалил вложениеZworklog_createdu+   Сделана запись о работеu)   сделал запись о работеZworklog_updatedu&   Журнал работ измененu&   изменил журнал работZworklog_deletedu$   Журнал работ удаленu$   удалил журнал работZmovedu   Перемещеноu    из проекта u    в проект u1   переместил в другой проектassignedu   Не установленu%   Задача назначена на u   , ожидает r   u'   назначил исполнителяrx   z, c             S   s   g | ]}t |jqS r1   )r,   r   ).0er1   r1   r2   
<listcomp>\  s    z5CmfNotify._prepare_notify_message.<locals>.<listcomp>u-   назначил соисполнителейZresolvedu   добавил решениеu1   В задаче добавлено решениеro   u   Задача завершенаu   завершил задачуZwork_startedu   Работа начатаu   начал работуZwork_stoppedu#   Работа остановленаu%   приостановил работуZreopenedu#   Задача переоткрытаu!   переоткрыл задачуchanged_statusZCLOSEDu   Задача закрытаu!   Статус изменен на u   , ожидаем u   изменил статус c "u   " на ""u   изменил статусZapprove_startedu.   Ожидается подтверждение u+   запустил подтверждениеZapprove_rejectedu6   Пользователь отклонил запросu   отклонил запросZapprove_success_fullu   Утверждение u    завершеноu)   утверждение завершеноZapprove_success_oneu:   Пользователь подтвердил запросu!   подтвердил запросZspectators_changedu'   изменены наблюдателиu4   Изменен состав наблюдателейu   <br>добавлен: u   <br>удален: responsiblerq   ZviewsZresult_textrV   updated)r   rx   r   T)
is_changedr   u   изменилu   Пришло событие u    по объекту )r   	html_diffZperm_policy_anonymousZperm_policy_guestchoicesr`   Zcaptionnewr   r   rV   oldr   waiting_forrq   r   	executorsr   joinr,   ra   Zcache_status_typeZ
spectatorsitemsr   Z_get_field_log_level)r=   r?   r   rJ   r   Z	anonymousZguestZresr   r   Znew_executorsr   Z	spectatorZskip_field_namesZtmp_listr   Z	field_objr|   r   r1   r1   r2   _prepare_notify_message  s   

*
*





















&













z!CmfNotify._prepare_notify_messagec          
   C   s   |j j}|jj}|jj}|jj}|j}tjj|d}	y$tj	j
|||||dd|	dsVdS W nH tk
rl   dS  tk
r }
 z|
jd |krdS  W dd}
~
X Y nX |jdkr|jrtjj|j|	dsdS |r|jdkr|jrtjj|j|	dsdS d	S )
u   
        Проверяет, что у получателя notify есть доступ к объекту
        Доп. проверяются права у private-комментариев
        )r_   readF)initial_acl_keyZobject_modelZobject_owner_idZ	object_idZobject_parent_idZaccess_levelZraise_errorchecking_personrx   N
CmfComment)Zcheck_for_userT)Zperm_effective_acl_idr`   r   cmf_owner_idr_   r   rg   rh   r   ZCmfAccessListZcheck_accessZCmfACLNotInitializedErrorZCmfACLNotFoundErrorr6   Zprivater   Zcheck_visibility)r=   r?   	member_idobj_commentr   Zobj_parent_idr   Zself_idr   r   r   r1   r1   r2   _check_perm_for_notify  s6    z CmfNotify._check_perm_for_notifyT)r   auditc            O   s  |j r
d S |sd S |sd S |js$d S tjr.d S d}|dkr>d}d }d }	|jdkrj|}|jj}|jdkrjd S |jdkr|}|jj}|jdkr|}|jj}|jdkr|jsd S |jd	kr|}	|j	j}|r| 
||}
n|	r| 
|	|}
n| 
||}
|jd
kr2|s2x.|
D ]&}tj||d |d djdd qW |s<d S x|
D ]}|d dkrXqB| ||}tjj d|d  d|j }|rBxt| D ]h\}}| j|||dsqtjj 6 tjj||||d |d d|krdnd|d W d Q R X qW qBW d S )NF)r   r   Tr   r   ZCmfAttachmentZCmfTimeTrackerHistoryrh   ZCmfGanttTask)r   ZCmfDocumentr   r|   )rV   r   r|   )r   )rx   r   r   r   )r   rc   )r?   r   r   rJ   rz   r   r   )Zdisable_auditZsmart_notifyr]   r   r   rV   r`   r|   r   Ztaskr   rg   r   r   r   r^   r   verbose_namer   r   r   utilr   Zdisable_aclr   r   )r=   r?   r   r   r   r6   rj   r   r   Zdependent_objZmsg_listZmsg_datar   r   r   Z	email_setr1   r1   r2   smart_all_place_notify  s    







z CmfNotify.smart_all_place_notifyc                s<   t  j|| td| j  d| jji| j gd d S )Nznotify-person-Z	notify_id)r   )superemitr   r   r   r_   r`   )selfr6   rj   )	__class__r1   r2   r   j  s
    
zCmfNotify.emitc             C   sh   |st jjj}dd|gdddgg}|r8|dd|jg | j|dgd}x|D ]}d|_|  qNW d S )Nr   z==rq   z!=ro   rp   )rv   rw   )r]   r^   r_   r`   r   listrq   r   )r=   r   r?   Z_filternotifiesr   r1   r1   r2   r   r  s    

zCmfNotify.close_open_notifiesc             C   sH   |st jj}| jdd|gdddggd}x|D ]}d|_|  q.W d S )Nr   z==rs   False)rv   T)r]   r^   r_   r   rs   r   )r=   r   r   r   r1   r1   r2   r     s    
z&CmfNotify.confirm_unconfirmed_notifiesc             C   s   |j dkr|j  }n&|j dkr,|g}ntd|j   d S xP|D ]H}tj|jj	}|d ksF|d slqFtj
j|||jd|j  d qFW d S )NZCmfPersonGrouprh   z,DEV: handle_mention_event unknown obj type: Zemail_if_mentionsu   Вас упомянули в )r?   r   r   rJ   )r   Z
rg_membersr   Z
all_nestedrL   rg   rh   ri   r_   r`   r   r   r   r   lower)r=   r?   Zevent_personZpersonsr   rk   r1   r1   r2   handle_mention_event  s    


zCmfNotify.handle_mention_event)	only_once
system_jobc             O   s   t j }|j| ||d d S )N)rA   )rg   CmfPluginMailBoxget_local_mailboxsend_message)Zrctp_torA   rD   r6   rj   mail_boxr1   r1   r2   r<     s    
zCmfNotify.process_emailc             O   s   t j }|| | d S )N)rg   CmfPluginSMSGateget_local_smsgater   )rP   r   r6   rj   sms_gater1   r1   r2   rM     s    
zCmfNotify.process_smsc             C   s\   t jj|jdgd}|rV|jrV|jdrV|j|jddsVd|j	 d|j
 d|j S |jS )	Nr   )r_   rw   ztask.sdzsdesk-client:default)ZprojectZ	role_code/z/?obj=:)rg   rh   r   r   r   r   r   Zin_project_rolerV   	ui_moduler   ra   r   )r=   r   r?   r   r1   r1   r2   _calc_notify_obj_link  s
    zCmfNotify._calc_notify_obj_linkc       
      C   s   |j s
d S |j j}d|j d|j d|j }|  }|rB| }| j||d}tdd | |_| j	
|}|j|d}tj }	|	j|||d d S )	Nr4   z] (z) )r   r?   T)rF   )r   )rA   )r"   r`   r   r   r   r7   r   rI   r   r8   r9   r:   rg   r   r   r   )
r=   r   r?   r@   rA   rB   re   rC   rD   r   r1   r1   r2   r     s    
zCmfNotify.send_email_notifyc             C   sf   |j std|j d d S tdd |j }|j}| d| }|j j}tj	 }|
|| d S )Nu4   SMS уведомление пользователю u_    не отправлено, не указан номер мобильного телефона.T)rF   rH   )r    rL   r   rI   r   r   r`   rg   r   r   r   )r=   r   r?   rN   rO   r   rP   r   r1   r1   r2   r     s    
zCmfNotify.send_sms_notifyz	@minutely)r   r   Zschedulec           
   O   s  t jjddgdddgdddggd}d	d
 |D }xZt jjdddgdddt tdd gdddgdd|gggdgdgd}|sP td|j d|  d }|j	rt
j|j	ddgd}|jry td t j|| d|_W n4 tk
r } ztd|  W d d }~X Y nX |jrty td t j|| d|_W n4 tk
rr } ztd|  W d d }~X Y nX d|_|  |j  q6W d S )Nz--rp   rr   z==Fru   T)rw   rv   c             S   s   h | ]
}|j qS r1   )rp   )r   r?   r1   r1   r2   	<setcomp>  s    z1CmfNotify.celery_minutely_hook.<locals>.<setcomp>ORZcmf_modified_at<   )ZminutesINr   )rv   rw   Zorder_byuB   Обработка отправки уведомлений для z: r   )Zinclude_deletedrw   u   Отправляем СМСz"models.CmfNotify.send_sms_notify: u   Отправляем emailz$models.CmfNotify.send_email_notify: )rg   r   Zslistr   r   rZ   r   printr_   rp   r   Zget_obj_by_idr   r   Zsms_done	ExceptionZloggingZ	exceptionr   r   Z
email_donerr   r   ZdpZcommit)r6   rj   Zforce_objectsZforce_object_idsr   r?   r   r1   r1   r2   celery_minutely_hook  sD    
"
"zCmfNotify.celery_minutely_hook)Nr   NFFr   N)N)NN)N).r(   r)   r*   r   r   Zcode_prefixZ_optionsZjinja2ZFileSystemLoaderospathr   r   ZPROJECT_DIRZ_loaderZEnvironmentr8   r   r   Zapi_methodsr   r3   classmethodrE   rQ   rl   r   r   r,   r   r   r   r   r   r   r   r   staticmethodZcmf_deferred_jobr<   rM   r   r   r   r   __classcell__r1   r1   )r   r2   r   	   s\   "'6   '9k  )^r   N)r   r   r   Zuuidr   Zdataclassesr   Zcmf.includeZ
cmf.fieldsr   r	   r
   r   r1   r1   r1   r2   <module>   s
   