162 lines
5.8 KiB
Python
162 lines
5.8 KiB
Python
"""
|
||
Django signals для автоматической генерации уведомлений в модуле Documents.
|
||
|
||
Обрабатывает события:
|
||
- post_save для Document - создание нового документа
|
||
- m2m_changed для Document.recipients - добавление конкретных получателей
|
||
- m2m_changed для Document.departments - добавление отделов
|
||
- post_save для DocumentAcknowledgement - проверка полного ознакомления
|
||
"""
|
||
|
||
import logging
|
||
|
||
from django.contrib.auth import get_user_model
|
||
from django.db.models.signals import m2m_changed, post_save
|
||
from django.dispatch import receiver
|
||
|
||
from ..models import Document, DocumentAcknowledgement
|
||
from .handlers import (
|
||
notify_all_acknowledged,
|
||
notify_all_employees,
|
||
notify_department_employees,
|
||
notify_specific_users,
|
||
)
|
||
|
||
logger = logging.getLogger(__name__)
|
||
Employee = get_user_model()
|
||
|
||
|
||
@receiver(post_save, sender=Document)
|
||
def create_document_notification(sender, instance, created, **kwargs):
|
||
"""
|
||
Создает уведомления при создании нового документа.
|
||
|
||
Уведомления отправляются:
|
||
- Всем активным сотрудникам (если sent_to_all=True)
|
||
- Сотрудникам выбранных отделов (через m2m_changed signal)
|
||
- Выбранным получателям (через m2m_changed signal)
|
||
"""
|
||
logger.debug(
|
||
"Document notification signal received",
|
||
extra={
|
||
"event": "document.notification.signal_received",
|
||
"document_id": instance.pk,
|
||
"object_created": created,
|
||
"sent_to_all": instance.sent_to_all,
|
||
},
|
||
)
|
||
|
||
if getattr(instance, "_suppress_document_notifications", False):
|
||
return
|
||
|
||
if not created:
|
||
return
|
||
|
||
document = instance
|
||
|
||
# Если документ отправляется всем - создаем уведомления напрямую
|
||
# channels.py автоматически отправит через Celery
|
||
if document.sent_to_all:
|
||
logger.info(
|
||
"Document notifications will be created for all employees",
|
||
extra={
|
||
"event": "document.notification.broadcast_started",
|
||
"document_id": document.pk,
|
||
},
|
||
)
|
||
notify_all_employees(document)
|
||
else:
|
||
logger.debug(
|
||
"Document notification broadcast deferred until recipients are assigned",
|
||
extra={
|
||
"event": "document.notification.broadcast_deferred",
|
||
"document_id": document.pk,
|
||
"reason": "recipient_assignment_pending",
|
||
},
|
||
)
|
||
|
||
|
||
@receiver(m2m_changed, sender=Document.recipients.through)
|
||
def notify_specific_recipients(sender, instance, action, pk_set, **kwargs):
|
||
"""
|
||
Уведомляет конкретных получателей при добавлении в список.
|
||
Использует быструю обработку для большого количества получателей.
|
||
"""
|
||
if getattr(instance, "_suppress_document_notifications", False):
|
||
return
|
||
|
||
if action != "post_add":
|
||
return
|
||
|
||
document = instance
|
||
|
||
# Не отправляем индивидуальные уведомления если документ для всех
|
||
if document.sent_to_all:
|
||
return
|
||
|
||
# Отправляем уведомления через handlers
|
||
notify_specific_users(document, pk_set)
|
||
|
||
|
||
@receiver(m2m_changed, sender=Document.departments.through)
|
||
def notify_department_employees_signal(sender, instance, action, pk_set, **kwargs):
|
||
"""
|
||
Уведомляет всех сотрудников выбранных отделов при добавлении отделов.
|
||
Уведомления получат ВСЕ текущие и будущие сотрудники этих отделов.
|
||
"""
|
||
if getattr(instance, "_suppress_document_notifications", False):
|
||
return
|
||
|
||
if action != "post_add":
|
||
return
|
||
|
||
document = instance
|
||
|
||
# Не отправляем если документ для всех
|
||
if document.sent_to_all:
|
||
return
|
||
|
||
# Отправляем уведомления через handlers
|
||
notify_department_employees(document, pk_set)
|
||
|
||
|
||
@receiver(post_save, sender=DocumentAcknowledgement)
|
||
def check_all_acknowledged(sender, instance, created, **kwargs):
|
||
"""
|
||
Проверяет, все ли получатели ознакомились с документом.
|
||
Если да - уведомляет загрузившего.
|
||
"""
|
||
if not created:
|
||
return
|
||
|
||
acknowledgement = instance
|
||
document = acknowledgement.document
|
||
if not document.acknowledgement_required:
|
||
logger.info(
|
||
"Document acknowledgement completion notification skipped",
|
||
extra={
|
||
"event": "document.acknowledgement_notification.skipped",
|
||
"document_id": document.pk,
|
||
"reason": "acknowledgement_optional",
|
||
},
|
||
)
|
||
return
|
||
|
||
from documents.audience import document_acknowledgement_audience
|
||
|
||
acknowledgement_audience = document_acknowledgement_audience(document)
|
||
total_recipients = acknowledgement_audience.count()
|
||
|
||
# Проверяем количество ознакомившихся
|
||
acknowledged_count = document.acknowledgements.filter(
|
||
user__in=acknowledgement_audience
|
||
).count()
|
||
|
||
# Если все ознакомились - уведомляем загрузившего
|
||
if (
|
||
acknowledged_count >= total_recipients
|
||
and total_recipients > 0
|
||
and document.uploaded_by
|
||
):
|
||
notify_all_acknowledged(document, total_recipients, acknowledged_count)
|