import django.db.models.deletion from django.conf import settings from django.db import migrations, models GUEST_ID_START = 900_000_000_000_001 GUEST_ID_MAX = 999_999_999_999_999 def create_guest_id_sequence(apps, schema_editor): if schema_editor.connection.vendor != "postgresql": return with schema_editor.connection.cursor() as cursor: cursor.execute( """ CREATE SEQUENCE IF NOT EXISTS guests_guest_id_seq START WITH 900000000000001 INCREMENT BY 1 MINVALUE 900000000000001 MAXVALUE 999999999999999 NO CYCLE """ ) def drop_guest_id_sequence(apps, schema_editor): if schema_editor.connection.vendor != "postgresql": return with schema_editor.connection.cursor() as cursor: cursor.execute("DROP SEQUENCE IF EXISTS guests_guest_id_seq") class Migration(migrations.Migration): initial = True dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("documents", "0015_delete_documentcomment"), ("employees", "0053_cleanup_department_role_permissions"), ] operations = [ migrations.RunPython(create_guest_id_sequence, drop_guest_id_sequence), migrations.CreateModel( name="Guest", fields=[ ( "id", models.BigIntegerField( editable=False, primary_key=True, serialize=False ), ), ("last_name", models.CharField(max_length=150, verbose_name="Фамилия")), ("first_name", models.CharField(max_length=150, verbose_name="Имя")), ( "patronymic", models.CharField( blank=True, max_length=150, verbose_name="Отчество" ), ), ( "birth_date", models.DateField( blank=True, null=True, verbose_name="Дата рождения" ), ), ( "phone", models.CharField(blank=True, max_length=64, verbose_name="Телефон"), ), ( "email", models.EmailField(blank=True, max_length=254, verbose_name="Email"), ), ( "organization", models.CharField( blank=True, max_length=255, verbose_name="Организация" ), ), ( "position", models.CharField( blank=True, max_length=255, verbose_name="Должность" ), ), ("comment", models.TextField(blank=True, verbose_name="Комментарий")), ( "is_active", models.BooleanField(default=True, verbose_name="Активен"), ), ( "ldap_enabled", models.BooleanField(default=False, verbose_name="LDAP в Active OU"), ), ( "ldap_username", models.CharField( blank=True, max_length=150, verbose_name="LDAP username" ), ), ( "ldap_upn", models.CharField( blank=True, max_length=255, verbose_name="LDAP UPN" ), ), ( "ldap_last_synced_at", models.DateTimeField( blank=True, null=True, verbose_name="Последняя LDAP синхронизация", ), ), ( "ldap_last_error", models.TextField(blank=True, verbose_name="Последняя LDAP ошибка"), ), ( "created_at", models.DateTimeField(auto_now_add=True, verbose_name="Создано"), ), ( "updated_at", models.DateTimeField(auto_now=True, verbose_name="Обновлено"), ), ( "created_by", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="created_guests", to=settings.AUTH_USER_MODEL, verbose_name="Создал", ), ), ], options={ "verbose_name": "Гость", "verbose_name_plural": "Гости", "ordering": ["last_name", "first_name", "id"], }, ), migrations.CreateModel( name="GuestVisit", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "inviter_snapshot_name", models.CharField( blank=True, max_length=255, verbose_name="ФИО приглашающего на момент создания", ), ), ( "inviter_snapshot_email", models.EmailField( blank=True, max_length=254, verbose_name="Email приглашающего на момент создания", ), ), ("purpose", models.TextField(verbose_name="Цель приглашения")), ( "visit_comment", models.TextField(blank=True, verbose_name="Комментарий заявителя"), ), ( "admin_comment", models.TextField( blank=True, verbose_name="Комментарий администратора" ), ), ( "status", models.CharField( choices=[ ("draft", "Черновик"), ("pending", "На рассмотрении"), ("needs_info", "Требуется информация"), ("approved", "Одобрено"), ("rejected", "Отклонено"), ("cancelled", "Отменено"), ("expired", "Истекло"), ("revoked", "Отозвано"), ], db_index=True, default="draft", max_length=24, verbose_name="Статус", ), ), ( "access_starts_at", models.DateTimeField( blank=True, null=True, verbose_name="Начало доступа" ), ), ( "access_expires_at", models.DateTimeField( blank=True, null=True, verbose_name="Окончание доступа" ), ), ( "all_day", models.BooleanField(default=True, verbose_name="Полные сутки"), ), ( "unlimited", models.BooleanField(default=False, verbose_name="Бессрочно"), ), ( "submitted_at", models.DateTimeField( blank=True, null=True, verbose_name="Отправлено на рассмотрение" ), ), ( "decided_at", models.DateTimeField( blank=True, null=True, verbose_name="Решение принято" ), ), ( "decision_comment", models.TextField(blank=True, verbose_name="Комментарий к решению"), ), ("cancelled_at", models.DateTimeField(blank=True, null=True)), ("cancel_reason", models.TextField(blank=True)), ("revoked_at", models.DateTimeField(blank=True, null=True)), ("revoke_reason", models.TextField(blank=True)), ("expired_at", models.DateTimeField(blank=True, null=True)), ("inviter_inactive", models.BooleanField(db_index=True, default=False)), ( "created_at", models.DateTimeField(auto_now_add=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_guest_visits", to=settings.AUTH_USER_MODEL, ), ), ( "decided_by", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="decided_guest_visits", to=settings.AUTH_USER_MODEL, verbose_name="Решение принял", ), ), ( "documents", models.ManyToManyField( blank=True, related_name="guest_visits", to="documents.document", verbose_name="Документы", ), ), ( "guest", models.ForeignKey( on_delete=django.db.models.deletion.PROTECT, related_name="visits", to="guests.guest", verbose_name="Гость", ), ), ( "host_department", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="guest_visits", to="employees.department", verbose_name="Отдел приглашающего", ), ), ( "inviter", models.ForeignKey( on_delete=django.db.models.deletion.PROTECT, related_name="guest_visits", to=settings.AUTH_USER_MODEL, verbose_name="Приглашающий", ), ), ( "revoked_by", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="revoked_guest_visits", to=settings.AUTH_USER_MODEL, ), ), ], options={ "verbose_name": "Гостевой визит", "verbose_name_plural": "Гостевые визиты", "ordering": ["-created_at"], "permissions": [ ("view_all_guestvisit", "Может просматривать все гостевые визиты"), ( "decide_guestvisit", "Может принимать решения по гостевым визитам", ), ("manage_guestaccount", "Может управлять гостевыми учетками"), ], }, ), migrations.CreateModel( name="GuestVisitEvent", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "event_type", models.CharField( choices=[ ("created", "Создано"), ("submitted", "Отправлено"), ("needs_info_requested", "Запрошена информация"), ("info_provided", "Информация предоставлена"), ("approved", "Одобрено"), ("rejected", "Отклонено"), ("decision_changed", "Решение изменено"), ("cancelled", "Отменено"), ("revoked", "Отозвано"), ("expired", "Истекло"), ("ldap_created", "LDAP создан"), ("ldap_updated", "LDAP обновлен"), ("ldap_enabled", "LDAP перемещен в Active OU"), ("ldap_disabled", "LDAP перемещен в Deactivated OU"), ("ldap_failed", "Ошибка LDAP"), ("ldap_skipped", "LDAP пропущен"), ("document_attached", "Документ прикреплен"), ("document_removed", "Документ удален"), ("inviter_inactive_detected", "Приглашающий неактивен"), ], db_index=True, max_length=48, verbose_name="Тип события", ), ), ("from_status", models.CharField(blank=True, max_length=24)), ("to_status", models.CharField(blank=True, max_length=24)), ("comment", models.TextField(blank=True)), ("metadata", models.JSONField(blank=True, default=dict)), ("created_at", models.DateTimeField(auto_now_add=True)), ( "actor", models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="guest_visit_events", to=settings.AUTH_USER_MODEL, verbose_name="Автор события", ), ), ( "visit", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="events", to="guests.guestvisit", verbose_name="Визит", ), ), ], options={ "verbose_name": "Событие гостевого визита", "verbose_name_plural": "События гостевых визитов", "ordering": ["-created_at", "-id"], }, ), migrations.AddIndex( model_name="guest", index=models.Index( fields=["last_name", "first_name"], name="guest_name_idx" ), ), migrations.AddIndex( model_name="guest", index=models.Index(fields=["email"], name="guest_email_idx"), ), migrations.AddIndex( model_name="guest", index=models.Index(fields=["phone"], name="guest_phone_idx"), ), migrations.AddIndex( model_name="guest", index=models.Index(fields=["ldap_enabled"], name="guest_ldap_enabled_idx"), ), migrations.AddConstraint( model_name="guest", constraint=models.CheckConstraint( condition=models.Q( ("id__gte", GUEST_ID_START), ("id__lte", GUEST_ID_MAX) ), name="guest_id_in_guest_range", ), ), migrations.AddIndex( model_name="guestvisit", index=models.Index( fields=["status", "created_at"], name="guestvisit_status_created_idx" ), ), migrations.AddIndex( model_name="guestvisit", index=models.Index( fields=["inviter", "created_at"], name="guestvisit_inviter_created_idx" ), ), migrations.AddIndex( model_name="guestvisit", index=models.Index( fields=["access_starts_at", "access_expires_at"], name="guestvisit_access_idx", ), ), migrations.AddIndex( model_name="guestvisit", index=models.Index( fields=["guest", "status"], name="guestvisit_guest_status_idx" ), ), migrations.AddConstraint( model_name="guestvisit", constraint=models.CheckConstraint( condition=models.Q( ("unlimited", True), ("access_expires_at__isnull", True), ("access_starts_at__isnull", True), ("access_starts_at__lt", models.F("access_expires_at")), _connector="OR", ), name="guest_visit_access_range_valid", ), ), migrations.AddIndex( model_name="guestvisitevent", index=models.Index( fields=["visit", "-created_at"], name="guestevent_visit_created_idx" ), ), migrations.AddIndex( model_name="guestvisitevent", index=models.Index( fields=["event_type", "-created_at"], name="guestevent_type_created_idx" ), ), ]