106 lines
4.9 KiB
Python
106 lines
4.9 KiB
Python
"""
|
||
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
|
||
})
|