62 lines
2.0 KiB
Python
62 lines
2.0 KiB
Python
"""
|
|
Signals for QI Projects.
|
|
|
|
- Sends a notification when a task is assigned.
|
|
- Keeps `team_members` in sync with the champion + manager of each linked
|
|
department whenever the `departments` M2M changes.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from django.db.models.signals import m2m_changed, post_save
|
|
from django.dispatch import receiver
|
|
|
|
from apps.projects.models import QIProject
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@receiver(post_save, sender="projects.QIProjectTask")
|
|
def notify_task_assignment(sender, instance, created, **kwargs):
|
|
"""Send an in-app notification when a QI task is assigned to a staff member."""
|
|
if not instance.assigned_to:
|
|
return
|
|
|
|
# Only notify on new assignments (creation with an assignee)
|
|
if not created:
|
|
return
|
|
|
|
user = getattr(instance.assigned_to, "user", None)
|
|
if not user:
|
|
return
|
|
|
|
try:
|
|
from apps.notifications.services import create_in_app_notification
|
|
|
|
create_in_app_notification(
|
|
user=user,
|
|
title=f"New QI Task: {instance.title}",
|
|
message=f"You have been assigned a task in project '{instance.project.name}'.",
|
|
notification_type="qi_task_assigned",
|
|
action_url=f"/projects/{instance.project.id}/",
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Failed to send QI task notification: {e}")
|
|
|
|
|
|
@receiver(m2m_changed, sender=QIProject.departments.through)
|
|
def sync_team_on_departments_change(sender, instance, action, **kwargs):
|
|
"""Rebuild the derived `team_members` set whenever the project's departments change.
|
|
|
|
Fires on `post_add` / `post_remove` / `post_clear` so that programmatic,
|
|
admin, and form-driven edits all stay consistent. The sync is idempotent.
|
|
"""
|
|
if action not in ("post_add", "post_remove", "post_clear"):
|
|
return
|
|
if not instance.pk:
|
|
return
|
|
try:
|
|
instance.sync_team_members_from_departments()
|
|
except Exception as e: # defensive: never break an M2M write on sync failure
|
|
logger.warning(f"Failed to sync QI team members for project {instance.pk}: {e}")
|