2026-09-07 19:43:48 +03:00

162 lines
5.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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)