565 lines
21 KiB
Python
565 lines
21 KiB
Python
# Generated by Django 4.2.7 on 2025-12-09 21:02
|
|
|
|
from django.conf import settings
|
|
import django.core.validators
|
|
from django.db import migrations, models
|
|
import django.db.models.deletion
|
|
import uuid
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
initial = True
|
|
|
|
dependencies = [
|
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name="Payment",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"uuid",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
unique=True,
|
|
verbose_name="UUID",
|
|
),
|
|
),
|
|
(
|
|
"amount",
|
|
models.DecimalField(
|
|
decimal_places=2,
|
|
max_digits=10,
|
|
validators=[django.core.validators.MinValueValidator(0)],
|
|
verbose_name="Сумма",
|
|
),
|
|
),
|
|
(
|
|
"currency",
|
|
models.CharField(
|
|
default="RUB", max_length=3, verbose_name="Валюта"
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("pending", "Ожидает"),
|
|
("processing", "Обрабатывается"),
|
|
("succeeded", "Успешно"),
|
|
("failed", "Ошибка"),
|
|
("cancelled", "Отменен"),
|
|
("refunded", "Возврат"),
|
|
],
|
|
db_index=True,
|
|
default="pending",
|
|
max_length=20,
|
|
verbose_name="Статус",
|
|
),
|
|
),
|
|
(
|
|
"payment_method",
|
|
models.CharField(
|
|
choices=[
|
|
("card", "Карта"),
|
|
("yookassa", "ЮKassa"),
|
|
("stripe", "Stripe"),
|
|
("paypal", "PayPal"),
|
|
("other", "Другое"),
|
|
],
|
|
max_length=20,
|
|
verbose_name="Метод оплаты",
|
|
),
|
|
),
|
|
(
|
|
"external_id",
|
|
models.CharField(
|
|
blank=True,
|
|
db_index=True,
|
|
max_length=255,
|
|
verbose_name="Внешний ID",
|
|
),
|
|
),
|
|
(
|
|
"provider_response",
|
|
models.JSONField(
|
|
blank=True, default=dict, verbose_name="Ответ провайдера"
|
|
),
|
|
),
|
|
("description", models.TextField(blank=True, verbose_name="Описание")),
|
|
(
|
|
"created_at",
|
|
models.DateTimeField(
|
|
auto_now_add=True, db_index=True, verbose_name="Дата создания"
|
|
),
|
|
),
|
|
(
|
|
"paid_at",
|
|
models.DateTimeField(
|
|
blank=True, null=True, verbose_name="Дата оплаты"
|
|
),
|
|
),
|
|
(
|
|
"failed_at",
|
|
models.DateTimeField(
|
|
blank=True, null=True, verbose_name="Дата ошибки"
|
|
),
|
|
),
|
|
(
|
|
"refunded_at",
|
|
models.DateTimeField(
|
|
blank=True, null=True, verbose_name="Дата возврата"
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Платеж",
|
|
"verbose_name_plural": "Платежи",
|
|
"db_table": "payments",
|
|
"ordering": ["-created_at"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="SubscriptionPlan",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"name",
|
|
models.CharField(
|
|
max_length=100, unique=True, verbose_name="Название"
|
|
),
|
|
),
|
|
(
|
|
"slug",
|
|
models.SlugField(max_length=100, unique=True, verbose_name="Слаг"),
|
|
),
|
|
("description", models.TextField(blank=True, verbose_name="Описание")),
|
|
(
|
|
"price",
|
|
models.DecimalField(
|
|
decimal_places=2,
|
|
max_digits=10,
|
|
validators=[django.core.validators.MinValueValidator(0)],
|
|
verbose_name="Цена",
|
|
),
|
|
),
|
|
(
|
|
"currency",
|
|
models.CharField(
|
|
default="RUB", max_length=3, verbose_name="Валюта"
|
|
),
|
|
),
|
|
(
|
|
"billing_period",
|
|
models.CharField(
|
|
choices=[
|
|
("monthly", "Ежемесячно"),
|
|
("quarterly", "Ежеквартально"),
|
|
("yearly", "Ежегодно"),
|
|
("lifetime", "Навсегда"),
|
|
],
|
|
default="monthly",
|
|
max_length=20,
|
|
verbose_name="Период оплаты",
|
|
),
|
|
),
|
|
(
|
|
"trial_days",
|
|
models.IntegerField(
|
|
default=0,
|
|
validators=[django.core.validators.MinValueValidator(0)],
|
|
verbose_name="Пробный период (дней)",
|
|
),
|
|
),
|
|
(
|
|
"max_clients",
|
|
models.IntegerField(
|
|
blank=True,
|
|
null=True,
|
|
validators=[django.core.validators.MinValueValidator(1)],
|
|
verbose_name="Максимум клиентов",
|
|
),
|
|
),
|
|
(
|
|
"max_lessons_per_month",
|
|
models.IntegerField(
|
|
blank=True,
|
|
null=True,
|
|
validators=[django.core.validators.MinValueValidator(1)],
|
|
verbose_name="Максимум занятий в месяц",
|
|
),
|
|
),
|
|
(
|
|
"max_storage_mb",
|
|
models.IntegerField(
|
|
default=1024,
|
|
validators=[django.core.validators.MinValueValidator(1)],
|
|
verbose_name="Максимум хранилища (МБ)",
|
|
),
|
|
),
|
|
(
|
|
"max_video_minutes_per_month",
|
|
models.IntegerField(
|
|
blank=True,
|
|
null=True,
|
|
validators=[django.core.validators.MinValueValidator(1)],
|
|
verbose_name="Максимум минут видео в месяц",
|
|
),
|
|
),
|
|
(
|
|
"allow_video_calls",
|
|
models.BooleanField(default=True, verbose_name="Видеозвонки"),
|
|
),
|
|
(
|
|
"allow_screen_sharing",
|
|
models.BooleanField(
|
|
default=True, verbose_name="Демонстрация экрана"
|
|
),
|
|
),
|
|
(
|
|
"allow_whiteboard",
|
|
models.BooleanField(
|
|
default=True, verbose_name="Интерактивная доска"
|
|
),
|
|
),
|
|
(
|
|
"allow_homework",
|
|
models.BooleanField(default=True, verbose_name="Домашние задания"),
|
|
),
|
|
(
|
|
"allow_materials",
|
|
models.BooleanField(default=True, verbose_name="Материалы"),
|
|
),
|
|
(
|
|
"allow_analytics",
|
|
models.BooleanField(default=True, verbose_name="Аналитика"),
|
|
),
|
|
(
|
|
"allow_telegram_bot",
|
|
models.BooleanField(default=False, verbose_name="Telegram бот"),
|
|
),
|
|
(
|
|
"allow_api_access",
|
|
models.BooleanField(default=False, verbose_name="API доступ"),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(
|
|
db_index=True, default=True, verbose_name="Активен"
|
|
),
|
|
),
|
|
(
|
|
"is_featured",
|
|
models.BooleanField(default=False, verbose_name="Рекомендуемый"),
|
|
),
|
|
(
|
|
"sort_order",
|
|
models.IntegerField(default=0, verbose_name="Порядок сортировки"),
|
|
),
|
|
(
|
|
"subscribers_count",
|
|
models.IntegerField(
|
|
default=0, verbose_name="Количество подписчиков"
|
|
),
|
|
),
|
|
(
|
|
"created_at",
|
|
models.DateTimeField(
|
|
auto_now_add=True, verbose_name="Дата создания"
|
|
),
|
|
),
|
|
(
|
|
"updated_at",
|
|
models.DateTimeField(auto_now=True, verbose_name="Дата обновления"),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Тарифный план",
|
|
"verbose_name_plural": "Тарифные планы",
|
|
"db_table": "subscription_plans",
|
|
"ordering": ["sort_order", "price"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="Subscription",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("trial", "Пробная"),
|
|
("active", "Активна"),
|
|
("past_due", "Просрочена"),
|
|
("cancelled", "Отменена"),
|
|
("expired", "Истекла"),
|
|
],
|
|
db_index=True,
|
|
default="trial",
|
|
max_length=20,
|
|
verbose_name="Статус",
|
|
),
|
|
),
|
|
("start_date", models.DateTimeField(verbose_name="Дата начала")),
|
|
("end_date", models.DateTimeField(verbose_name="Дата окончания")),
|
|
(
|
|
"trial_end_date",
|
|
models.DateTimeField(
|
|
blank=True,
|
|
null=True,
|
|
verbose_name="Дата окончания пробного периода",
|
|
),
|
|
),
|
|
(
|
|
"cancelled_at",
|
|
models.DateTimeField(
|
|
blank=True, null=True, verbose_name="Дата отмены"
|
|
),
|
|
),
|
|
(
|
|
"auto_renew",
|
|
models.BooleanField(default=True, verbose_name="Автопродление"),
|
|
),
|
|
(
|
|
"lessons_used",
|
|
models.IntegerField(default=0, verbose_name="Использовано занятий"),
|
|
),
|
|
(
|
|
"storage_used_mb",
|
|
models.IntegerField(
|
|
default=0, verbose_name="Использовано хранилища (МБ)"
|
|
),
|
|
),
|
|
(
|
|
"video_minutes_used",
|
|
models.IntegerField(
|
|
default=0, verbose_name="Использовано минут видео"
|
|
),
|
|
),
|
|
(
|
|
"created_at",
|
|
models.DateTimeField(
|
|
auto_now_add=True, verbose_name="Дата создания"
|
|
),
|
|
),
|
|
(
|
|
"updated_at",
|
|
models.DateTimeField(auto_now=True, verbose_name="Дата обновления"),
|
|
),
|
|
(
|
|
"plan",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.PROTECT,
|
|
related_name="subscriptions",
|
|
to="subscriptions.subscriptionplan",
|
|
verbose_name="Тарифный план",
|
|
),
|
|
),
|
|
(
|
|
"user",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="subscriptions",
|
|
to=settings.AUTH_USER_MODEL,
|
|
verbose_name="Пользователь",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Подписка",
|
|
"verbose_name_plural": "Подписки",
|
|
"db_table": "subscriptions",
|
|
"ordering": ["-created_at"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="PaymentHistory",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
("status", models.CharField(max_length=20, verbose_name="Статус")),
|
|
("message", models.TextField(blank=True, verbose_name="Сообщение")),
|
|
(
|
|
"data",
|
|
models.JSONField(blank=True, default=dict, verbose_name="Данные"),
|
|
),
|
|
(
|
|
"created_at",
|
|
models.DateTimeField(
|
|
auto_now_add=True, db_index=True, verbose_name="Дата"
|
|
),
|
|
),
|
|
(
|
|
"payment",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="history",
|
|
to="subscriptions.payment",
|
|
verbose_name="Платеж",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "История платежа",
|
|
"verbose_name_plural": "История платежей",
|
|
"db_table": "payment_history",
|
|
"ordering": ["-created_at"],
|
|
},
|
|
),
|
|
migrations.AddField(
|
|
model_name="payment",
|
|
name="subscription",
|
|
field=models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="payments",
|
|
to="subscriptions.subscription",
|
|
verbose_name="Подписка",
|
|
),
|
|
),
|
|
migrations.AddField(
|
|
model_name="payment",
|
|
name="user",
|
|
field=models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="payments",
|
|
to=settings.AUTH_USER_MODEL,
|
|
verbose_name="Пользователь",
|
|
),
|
|
),
|
|
migrations.CreateModel(
|
|
name="SubscriptionUsageLog",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"usage_type",
|
|
models.CharField(
|
|
choices=[
|
|
("lesson", "Занятие"),
|
|
("storage", "Хранилище"),
|
|
("video_minutes", "Минуты видео"),
|
|
],
|
|
max_length=20,
|
|
verbose_name="Тип использования",
|
|
),
|
|
),
|
|
("amount", models.IntegerField(verbose_name="Количество")),
|
|
(
|
|
"description",
|
|
models.CharField(
|
|
blank=True, max_length=255, verbose_name="Описание"
|
|
),
|
|
),
|
|
(
|
|
"created_at",
|
|
models.DateTimeField(
|
|
auto_now_add=True, db_index=True, verbose_name="Дата"
|
|
),
|
|
),
|
|
(
|
|
"subscription",
|
|
models.ForeignKey(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="usage_logs",
|
|
to="subscriptions.subscription",
|
|
verbose_name="Подписка",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Лог использования",
|
|
"verbose_name_plural": "Логи использования",
|
|
"db_table": "subscription_usage_logs",
|
|
"ordering": ["-created_at"],
|
|
"indexes": [
|
|
models.Index(
|
|
fields=["subscription", "created_at"],
|
|
name="subscriptio_subscri_7edac6_idx",
|
|
),
|
|
models.Index(
|
|
fields=["usage_type"], name="subscriptio_usage_t_bbd759_idx"
|
|
),
|
|
],
|
|
},
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="subscription",
|
|
index=models.Index(
|
|
fields=["user", "status"], name="subscriptio_user_id_8d58fd_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="subscription",
|
|
index=models.Index(
|
|
fields=["end_date"], name="subscriptio_end_dat_763002_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="subscription",
|
|
index=models.Index(fields=["status"], name="subscriptio_status_572d44_idx"),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="payment",
|
|
index=models.Index(
|
|
fields=["user", "created_at"], name="payments_user_id_03af7e_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="payment",
|
|
index=models.Index(
|
|
fields=["subscription"], name="payments_subscri_9bd444_idx"
|
|
),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="payment",
|
|
index=models.Index(fields=["status"], name="payments_status_d621e5_idx"),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="payment",
|
|
index=models.Index(
|
|
fields=["external_id"], name="payments_externa_f1691b_idx"
|
|
),
|
|
),
|
|
]
|