uchill/backend/apps/schedule/signals.py

106 lines
4.9 KiB
Python
Raw 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.

"""
Signals для приложения schedule.
Автоматические действия при изменении расписания.
"""
from django.db.models.signals import post_save, pre_delete, pre_save
from django.dispatch import receiver
from django.utils import timezone
from datetime import timedelta
from .models import Lesson
from apps.notifications.tasks import send_lesson_notification, send_lesson_completion_confirmation_telegram
@receiver(post_save, sender=Lesson)
def lesson_saved(sender, instance, created, **kwargs):
"""
Обработка создания или изменения занятия.
При создании:
- Отправка уведомления ментору и клиенту
- Планирование напоминания перед занятием
При изменении:
- Отправка уведомления об изменении времени/статуса
"""
if created:
# Новое занятие создано
send_lesson_notification.delay(
lesson_id=instance.id,
notification_type='lesson_created'
)
# Если занятие создано сразу в статусе completed (задним числом) — отправляем подтверждение в Telegram
if instance.status == 'completed':
send_lesson_completion_confirmation_telegram.delay(instance.id)
# Напоминания отправляются периодической задачей send_lesson_reminders
# (проверяет флаги reminder_24h_sent, reminder_1h_sent, reminder_15m_sent)
else:
# Занятие изменено
# Проверяем, что именно изменилось
if instance.tracker.has_changed('start_time') or instance.tracker.has_changed('end_time'):
# Время изменилось
send_lesson_notification.delay(
lesson_id=instance.id,
notification_type='lesson_rescheduled'
)
if instance.tracker.has_changed('status'):
# При переводе в completed — всегда отправляем подтверждение в Telegram (с кнопками «состоялось»/«отменилось»)
# Работает для ручного завершения и для занятий, созданных/завершённых задним числом
if instance.status == 'completed':
send_lesson_completion_confirmation_telegram.delay(instance.id)
# Общие уведомления — не отправляем, если занятие уже в прошлом
# (коррекция статуса/стоимости после факта, например отмена задним числом)
ref_time = instance.end_time or instance.start_time
if ref_time and ref_time < timezone.now():
return # Занятие уже прошло — пропускаем lesson_cancelled / lesson_completed
if instance.status == 'cancelled':
send_lesson_notification.delay(
lesson_id=instance.id,
notification_type='lesson_cancelled'
)
elif instance.status == 'completed':
send_lesson_notification.delay(
lesson_id=instance.id,
notification_type='lesson_completed'
)
@receiver(pre_delete, sender=Lesson)
def lesson_deleted(sender, instance, **kwargs):
"""
Обработка удаления занятия.
Отправка уведомления об отмене.
"""
if instance.status != 'cancelled':
send_lesson_notification.delay(
lesson_id=instance.id,
notification_type='lesson_cancelled'
)
@receiver(pre_save, sender=Lesson)
def lesson_before_save(sender, instance, **kwargs):
"""
Действия перед сохранением занятия.
Инициализация tracker для отслеживания изменений.
"""
if not hasattr(instance, 'tracker'):
# Создаем простой tracker для отслеживания изменений
if instance.pk:
try:
old_instance = Lesson.objects.get(pk=instance.pk)
instance.tracker = type('obj', (object,), {
'has_changed': lambda field: getattr(old_instance, field) != getattr(instance, field)
})
except Lesson.DoesNotExist:
instance.tracker = type('obj', (object,), {
'has_changed': lambda field: False
})
else:
instance.tracker = type('obj', (object,), {
'has_changed': lambda field: False
})