# Generated by Django 4.2.7 on 2025-12-09 21:02 import apps.schedule.models from django.conf import settings import django.core.validators from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): initial = True dependencies = [ ("materials", "0001_initial"), ("users", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name="Lesson", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "start_time", models.DateTimeField(db_index=True, verbose_name="Время начала"), ), ( "end_time", models.DateTimeField(db_index=True, verbose_name="Время окончания"), ), ( "duration", models.IntegerField( default=60, help_text="Длительность занятия в минутах (15-480)", validators=[ django.core.validators.MinValueValidator(15), django.core.validators.MaxValueValidator(480), ], verbose_name="Длительность (минуты)", ), ), ( "title", models.CharField( help_text="Краткое название занятия", max_length=200, verbose_name="Название", ), ), ( "description", models.TextField( blank=True, help_text="Подробное описание занятия", verbose_name="Описание", ), ), ( "subject", models.CharField( blank=True, help_text="Предмет обучения (математика, физика и т.д.)", max_length=100, verbose_name="Предмет", ), ), ( "status", models.CharField( choices=[ ("scheduled", "Запланировано"), ("in_progress", "В процессе"), ("completed", "Завершено"), ("cancelled", "Отменено"), ("rescheduled", "Перенесено"), ], db_index=True, default="scheduled", max_length=20, verbose_name="Статус", ), ), ( "cancellation_reason", models.TextField(blank=True, verbose_name="Причина отмены"), ), ( "cancelled_at", models.DateTimeField( blank=True, null=True, verbose_name="Дата отмены" ), ), ( "meeting_url", models.URLField( blank=True, help_text="Ссылка на видеоконференцию", max_length=500, verbose_name="Ссылка на встречу", ), ), ( "mentor_notes", models.TextField( blank=True, help_text="Приватные заметки ментора о занятии", verbose_name="Заметки ментора", ), ), ( "homework_text", models.TextField( blank=True, help_text="Описание домашнего задания, выданного по результатам занятия", verbose_name="Домашнее задание", ), ), ( "mentor_grade", models.IntegerField( blank=True, help_text="Оценка работы студента на занятии (0-100)", null=True, verbose_name="Оценка ментора", ), ), ( "school_grade", models.IntegerField( blank=True, help_text="Текущая оценка студента в школе (0-100)", null=True, verbose_name="Оценка в школе", ), ), ( "price", models.DecimalField( blank=True, decimal_places=2, help_text="Стоимость занятия в рублях", max_digits=10, null=True, verbose_name="Стоимость", ), ), ( "reminder_sent", models.BooleanField( default=False, verbose_name="Напоминание отправлено" ), ), ( "created_at", models.DateTimeField( auto_now_add=True, null=True, verbose_name="Дата создания" ), ), ( "updated_at", models.DateTimeField(auto_now=True, verbose_name="Дата обновления"), ), ( "cancelled_by", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="cancelled_lessons", to=settings.AUTH_USER_MODEL, verbose_name="Отменено пользователем", ), ), ( "client", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="lessons", to="users.client", verbose_name="Клиент", ), ), ( "group", models.ForeignKey( blank=True, help_text="Учебная группа, если занятие групповое", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="lessons", to="users.group", verbose_name="Группа", ), ), ( "mentor", models.ForeignKey( limit_choices_to={"role": "mentor"}, on_delete=django.db.models.deletion.CASCADE, related_name="mentor_lessons", to=settings.AUTH_USER_MODEL, verbose_name="Ментор", ), ), ( "rescheduled_from", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="rescheduled_to", to="schedule.lesson", verbose_name="Перенесено из", ), ), ], options={ "verbose_name": "Занятие", "verbose_name_plural": "Занятия", "db_table": "lessons", "ordering": ["start_time"], }, ), migrations.CreateModel( name="LessonTemplate", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("title", models.CharField(max_length=200, verbose_name="Название")), ("description", models.TextField(blank=True, verbose_name="Описание")), ( "subject", models.CharField( blank=True, max_length=100, verbose_name="Предмет" ), ), ( "duration", models.IntegerField( default=60, validators=[ django.core.validators.MinValueValidator(15), django.core.validators.MaxValueValidator(480), ], verbose_name="Длительность (минуты)", ), ), ( "is_active", models.BooleanField(default=True, verbose_name="Активен"), ), ( "meeting_url", models.URLField( blank=True, max_length=500, verbose_name="Ссылка на встречу" ), ), ( "color", models.CharField( default="#3B82F6", help_text="HEX код цвета для отображения в календаре", max_length=7, verbose_name="Цвет", ), ), ( "created_at", models.DateTimeField( auto_now_add=True, null=True, verbose_name="Дата создания" ), ), ( "updated_at", models.DateTimeField(auto_now=True, verbose_name="Дата обновления"), ), ( "mentor", models.ForeignKey( limit_choices_to={"role": "mentor"}, on_delete=django.db.models.deletion.CASCADE, related_name="lesson_templates", to=settings.AUTH_USER_MODEL, verbose_name="Ментор", ), ), ], options={ "verbose_name": "Шаблон занятия", "verbose_name_plural": "Шаблоны занятий", "db_table": "lesson_templates", "ordering": ["mentor", "title"], }, ), migrations.CreateModel( name="LessonFile", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "file", models.FileField( blank=True, max_length=500, null=True, upload_to=apps.schedule.models.lesson_file_upload_path, validators=[ django.core.validators.FileExtensionValidator( allowed_extensions=[ "pdf", "doc", "docx", "txt", "jpg", "jpeg", "png", "zip", "rar", ] ) ], verbose_name="Файл", ), ), ( "source", models.CharField( choices=[ ("uploaded", "Загружен при завершении"), ("material", "Из учебных материалов"), ], default="uploaded", max_length=20, verbose_name="Источник", ), ), ( "filename", models.CharField(max_length=255, verbose_name="Название файла"), ), ( "file_size", models.BigIntegerField( blank=True, null=True, verbose_name="Размер файла (bytes)" ), ), ("description", models.TextField(blank=True, verbose_name="Описание")), ( "created_at", models.DateTimeField( auto_now_add=True, verbose_name="Дата создания" ), ), ( "lesson", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="files", to="schedule.lesson", verbose_name="Урок", ), ), ( "material", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="lesson_files", to="materials.material", verbose_name="Учебный материал", ), ), ( "uploaded_by", models.ForeignKey( null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="uploaded_lesson_files", to=settings.AUTH_USER_MODEL, verbose_name="Загрузил", ), ), ], options={ "verbose_name": "Файл урока", "verbose_name_plural": "Файлы уроков", "db_table": "lesson_files", "ordering": ["-created_at"], }, ), migrations.AddField( model_name="lesson", name="template", field=models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="lessons", to="schedule.lessontemplate", verbose_name="Шаблон", ), ), migrations.CreateModel( name="Availability", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "day_of_week", models.IntegerField( blank=True, choices=[ (0, "Понедельник"), (1, "Вторник"), (2, "Среда"), (3, "Четверг"), (4, "Пятница"), (5, "Суббота"), (6, "Воскресенье"), ], help_text="Для еженедельного повторения", null=True, verbose_name="День недели", ), ), ( "specific_date", models.DateField( blank=True, help_text="Для разовой доступности", null=True, verbose_name="Конкретная дата", ), ), ("start_time", models.TimeField(verbose_name="Время начала")), ("end_time", models.TimeField(verbose_name="Время окончания")), ( "is_recurring", models.BooleanField( default=True, help_text="Повторяется ли еженедельно", verbose_name="Повторяющаяся", ), ), ( "is_active", models.BooleanField(default=True, verbose_name="Активна"), ), ( "exception_dates", models.JSONField( blank=True, default=list, help_text="Список дат в формате YYYY-MM-DD", verbose_name="Даты исключений", ), ), ("notes", models.TextField(blank=True, verbose_name="Заметки")), ( "created_at", models.DateTimeField( auto_now_add=True, verbose_name="Дата создания" ), ), ( "updated_at", models.DateTimeField(auto_now=True, verbose_name="Дата обновления"), ), ( "mentor", models.ForeignKey( limit_choices_to={"role": "mentor"}, on_delete=django.db.models.deletion.CASCADE, related_name="availabilities", to=settings.AUTH_USER_MODEL, verbose_name="Ментор", ), ), ], options={ "verbose_name": "Доступность", "verbose_name_plural": "Доступность", "db_table": "availabilities", "ordering": ["mentor", "day_of_week", "start_time"], }, ), migrations.CreateModel( name="TimeSlot", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "start_time", models.DateTimeField(db_index=True, verbose_name="Время начала"), ), ( "end_time", models.DateTimeField(db_index=True, verbose_name="Время окончания"), ), ( "is_available", models.BooleanField( default=True, help_text="Свободен ли слот для бронирования", verbose_name="Доступен", ), ), ( "is_booked", models.BooleanField(default=False, verbose_name="Забронирован"), ), ( "is_recurring", models.BooleanField( default=False, help_text="Повторяется ли этот слот еженедельно", verbose_name="Повторяющийся", ), ), ( "recurring_day", models.IntegerField( blank=True, help_text="0=Понедельник, 6=Воскресенье", null=True, validators=[ django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(6), ], verbose_name="День недели", ), ), ( "created_at", models.DateTimeField( auto_now_add=True, null=True, verbose_name="Дата создания" ), ), ( "updated_at", models.DateTimeField(auto_now=True, verbose_name="Дата обновления"), ), ( "lesson", models.OneToOneField( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="time_slot", to="schedule.lesson", verbose_name="Занятие", ), ), ( "mentor", models.ForeignKey( limit_choices_to={"role": "mentor"}, on_delete=django.db.models.deletion.CASCADE, related_name="time_slots", to=settings.AUTH_USER_MODEL, verbose_name="Ментор", ), ), ], options={ "verbose_name": "Временной слот", "verbose_name_plural": "Временные слоты", "db_table": "time_slots", "ordering": ["start_time"], "indexes": [ models.Index( fields=["mentor", "start_time"], name="time_slots_mentor__87e9a7_idx", ), models.Index( fields=["is_available", "is_booked"], name="time_slots_is_avai_b83db3_idx", ), models.Index( fields=["start_time", "end_time"], name="time_slots_start_t_7c83d2_idx", ), ], }, ), migrations.AddConstraint( model_name="timeslot", constraint=models.CheckConstraint( check=models.Q(("end_time__gt", models.F("start_time"))), name="timeslot_end_after_start", ), ), migrations.AddIndex( model_name="lessonfile", index=models.Index( fields=["lesson"], name="lesson_file_lesson__d6fb1a_idx" ), ), migrations.AddIndex( model_name="lessonfile", index=models.Index( fields=["material"], name="lesson_file_materia_35443f_idx" ), ), migrations.AddIndex( model_name="lesson", index=models.Index( fields=["mentor", "start_time"], name="lessons_mentor__e6e1ba_idx" ), ), migrations.AddIndex( model_name="lesson", index=models.Index( fields=["client", "start_time"], name="lessons_client__6fbdab_idx" ), ), migrations.AddIndex( model_name="lesson", index=models.Index( fields=["status", "start_time"], name="lessons_status_a82e95_idx" ), ), migrations.AddIndex( model_name="lesson", index=models.Index( fields=["start_time", "end_time"], name="lessons_start_t_f960c9_idx" ), ), migrations.AddConstraint( model_name="lesson", constraint=models.CheckConstraint( check=models.Q(("end_time__gt", models.F("start_time"))), name="lesson_end_after_start", ), ), migrations.AddIndex( model_name="availability", index=models.Index( fields=["mentor", "is_active"], name="availabilit_mentor__4001a0_idx" ), ), migrations.AddIndex( model_name="availability", index=models.Index( fields=["day_of_week", "start_time"], name="availabilit_day_of__7b54ec_idx", ), ), migrations.AddIndex( model_name="availability", index=models.Index( fields=["specific_date"], name="availabilit_specifi_49965a_idx" ), ), migrations.AddConstraint( model_name="availability", constraint=models.CheckConstraint( check=models.Q(("end_time__gt", models.F("start_time"))), name="availability_end_after_start", ), ), ]