from datetime import datetime, time from decimal import Decimal from zoneinfo import ZoneInfo import pytest from django.utils import timezone from apps.jobs.models import Application, Feedback, ScoreRun from apps.jobs.services.scoring import score_and_save from apps.notifications.models import ReminderOutbox from apps.notifications.services import ( create_closing_reminders, create_follow_up_reminders, create_top_match_reminders, ) @pytest.mark.django_db def test_closing_reminder_is_idempotent_and_skips_hidden(profile, job): zone = ZoneInfo(profile.timezone) now = timezone.now().astimezone(zone) job.valid_through = datetime( year=now.year, month=now.month, day=now.day, hour=20, tzinfo=zone, ) job.save(update_fields=["valid_through"]) Feedback.objects.create( user=profile.user, profile=profile, job=job, action=Feedback.Action.HIDE, ) assert create_closing_reminders(profile, now=now) == [] Feedback.objects.filter(user=profile.user, profile=profile, job=job).delete() first = create_closing_reminders(profile, now=now)[0] second = create_closing_reminders(profile, now=now)[0] assert first.pk == second.pk assert first.status == ReminderOutbox.Status.PENDING @pytest.mark.django_db def test_follow_up_reminder_respects_configured_weekdays(profile, job): zone = ZoneInfo(profile.timezone) now = timezone.now().astimezone(zone) follow_date = now.date() Application.objects.create( user=profile.user, job=job, follow_up_date=follow_date, status=Application.Status.APPLIED, notes="", ) profile.follow_up_weekdays = [(follow_date.weekday() + 1) % 7] profile.save(update_fields=["follow_up_weekdays"]) assert create_follow_up_reminders(profile, now=now) == [] profile.follow_up_weekdays = [follow_date.weekday()] profile.save(update_fields=["follow_up_weekdays"]) reminders = create_follow_up_reminders(profile, now=now) assert len(reminders) == 1 assert reminders[0].reminder_type == ReminderOutbox.ReminderType.FOLLOW_UP @pytest.mark.django_db def test_top_match_reminder_requires_threshold_and_profile_setting(profile, job): profile.top_match_reminders_enabled = True profile.top_match_threshold = 90 profile.save(update_fields=["top_match_reminders_enabled", "top_match_threshold"]) score = score_and_save(job, profile) score.recommendation = ScoreRun.Recommendation.STRONG score.score = 85 score.confidence = Decimal("0.9") score.save(update_fields=["recommendation", "score", "confidence"]) assert create_top_match_reminders(profile) == [] score.score = 95 score.confidence = Decimal("0.90") score.save(update_fields=["score", "confidence"]) score.confidence = Decimal("0.84") score.save(update_fields=["confidence"]) assert create_top_match_reminders(profile) == [] score.confidence = Decimal("0.86") score.save(update_fields=["confidence"]) reminders = create_top_match_reminders(profile) assert len(reminders) == 1 assert reminders[0].reminder_type == ReminderOutbox.ReminderType.TOP_MATCH profile.top_match_reminders_enabled = False profile.save(update_fields=["top_match_reminders_enabled"]) assert create_top_match_reminders(profile) == [] @pytest.mark.django_db def test_reminder_obeys_quiet_hours_and_empty_recipient(profile, job): zone = ZoneInfo(profile.timezone) now = timezone.now().astimezone(zone).replace(hour=6, minute=30, second=0, microsecond=0) job.valid_through = datetime( year=now.year, month=now.month, day=now.day, hour=18, tzinfo=zone, ) job.save(update_fields=["valid_through"]) profile.user.email = "" profile.user.save(update_fields=["email"]) assert create_closing_reminders(profile, now=now)[0].status == ReminderOutbox.Status.SKIPPED profile.user.email = "reminder@example.invalid" profile.user.save(update_fields=["email"]) reminder = create_closing_reminders(profile, now=now)[0] assert reminder.status == ReminderOutbox.Status.PENDING assert reminder.scheduled_for.timetz().replace(tzinfo=None) == time(7, 0) @pytest.mark.django_db def test_reminder_service_handles_dst_dates(profile, job): zone = ZoneInfo(profile.timezone) now = datetime(2026, 10, 25, 1, 30, tzinfo=zone) job.valid_through = now.replace(hour=20) job.save(update_fields=["valid_through"]) reminder = create_closing_reminders(profile, now=now)[0] assert reminder.scheduled_for.tzinfo is not None assert reminder.scheduled_for.tzinfo.key == "Europe/Brussels"