131 lines
8.5 KiB
Python
131 lines
8.5 KiB
Python
# Generated by Django 5.1.1 on 2026-09-05 07:03
|
|
|
|
import django.core.validators
|
|
import django.db.models.deletion
|
|
import uuid
|
|
from django.conf import settings
|
|
from django.db import migrations, models
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
initial = True
|
|
|
|
dependencies = [
|
|
('messaging', '0001_initial'),
|
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name='SLAConfig',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('priority', models.CharField(max_length=15, unique=True)),
|
|
('first_response_minutes', models.PositiveIntegerField()),
|
|
('resolution_minutes', models.PositiveIntegerField()),
|
|
('is_active', models.BooleanField(default=True)),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='TicketCategory',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
('updated_at', models.DateTimeField(auto_now=True)),
|
|
('title', models.CharField(max_length=100)),
|
|
('slug', models.SlugField(unique=True)),
|
|
('description', models.TextField(blank=True)),
|
|
('icon', models.CharField(blank=True, max_length=50)),
|
|
('sort_order', models.PositiveIntegerField(default=0)),
|
|
('is_active', models.BooleanField(default=True)),
|
|
],
|
|
options={
|
|
'ordering': ['sort_order', 'title'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Ticket',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
('updated_at', models.DateTimeField(auto_now=True)),
|
|
('public_id', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
|
('ticket_number', models.CharField(editable=False, max_length=30, unique=True)),
|
|
('subject', models.CharField(max_length=200, validators=[django.core.validators.MinLengthValidator(5)])),
|
|
('status', models.CharField(choices=[('NEW', 'جدید'), ('OPEN', 'باز'), ('WAITING_CUSTOMER', 'در انتظار مشتری'), ('WAITING_STAFF', 'در انتظار کارشناس'), ('RESOLVED', 'حل\u200cشده'), ('CLOSED', 'بسته'), ('REOPENED', 'بازگشایی\u200cشده')], db_index=True, default='NEW', max_length=25)),
|
|
('priority', models.CharField(choices=[('NORMAL', 'عادی'), ('IMPORTANT', 'مهم'), ('URGENT', 'فوری')], db_index=True, default='NORMAL', max_length=15)),
|
|
('origin_visibility', models.CharField(choices=[('PUBLIC', 'عمومی'), ('SELECTED', 'کارشناس انتخابی')], default='PUBLIC', max_length=15)),
|
|
('last_activity_at', models.DateTimeField(db_index=True)),
|
|
('first_response_at', models.DateTimeField(blank=True, null=True)),
|
|
('last_customer_message_at', models.DateTimeField(blank=True, null=True)),
|
|
('last_staff_message_at', models.DateTimeField(blank=True, null=True)),
|
|
('first_response_due_at', models.DateTimeField(blank=True, null=True)),
|
|
('resolution_due_at', models.DateTimeField(blank=True, null=True)),
|
|
('resolved_at', models.DateTimeField(blank=True, null=True)),
|
|
('closed_at', models.DateTimeField(blank=True, null=True)),
|
|
('reopened_at', models.DateTimeField(blank=True, null=True)),
|
|
('customer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='customer_tickets', to=settings.AUTH_USER_MODEL)),
|
|
('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='owned_tickets', to=settings.AUTH_USER_MODEL)),
|
|
('selected_expert', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='selected_tickets', to=settings.AUTH_USER_MODEL)),
|
|
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='tickets', to='tickets.ticketcategory')),
|
|
],
|
|
options={
|
|
'ordering': ['-last_activity_at'],
|
|
'permissions': [('view_all_tickets', 'Can view all tickets'), ('claim_ticket', 'Can claim ticket'), ('transfer_ticket', 'Can transfer ticket'), ('share_ticket', 'Can share ticket'), ('change_ticket_priority', 'Can change ticket priority'), ('view_customer_history', 'Can view customer history')],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='TicketEvent',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('event_type', models.CharField(choices=[('CREATED', 'ایجاد'), ('CLAIMED', 'برداشت'), ('TRANSFERRED', 'انتقال'), ('SHARED', 'اشتراک'), ('ACCESS_REVOKED', 'لغو دسترسی'), ('STATUS_CHANGED', 'تغییر وضعیت'), ('PRIORITY_CHANGED', 'تغییر اولویت'), ('REOPENED', 'بازگشایی'), ('RESOLVED', 'حل'), ('CLOSED', 'بستن')], max_length=30)),
|
|
('metadata', models.JSONField(blank=True, default=dict)),
|
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
('actor', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
|
|
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='tickets.ticket')),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='TicketReadState',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('last_read_at', models.DateTimeField()),
|
|
('last_read_message', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='messaging.message')),
|
|
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tickets.ticket')),
|
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='TicketAccessGrant',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('permission_level', models.CharField(choices=[('VIEW_ONLY', 'فقط مشاهده'), ('REPLY', 'پاسخ'), ('FULL', 'کامل')], default='FULL', max_length=15)),
|
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
('revoked_at', models.DateTimeField(blank=True, null=True)),
|
|
('granted_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='granted_ticket_access', to=settings.AUTH_USER_MODEL)),
|
|
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='access_grants', to='tickets.ticket')),
|
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ticket_grants', to=settings.AUTH_USER_MODEL)),
|
|
],
|
|
options={
|
|
'constraints': [models.UniqueConstraint(condition=models.Q(('revoked_at__isnull', True)), fields=('ticket', 'user'), name='unique_active_ticket_grant')],
|
|
},
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='ticket',
|
|
index=models.Index(fields=['status', 'last_activity_at'], name='tickets_tic_status_dbef56_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='ticket',
|
|
index=models.Index(fields=['owner', 'status'], name='tickets_tic_owner_i_70fd59_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='ticket',
|
|
index=models.Index(fields=['selected_expert', 'status'], name='tickets_tic_selecte_71a761_idx'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='ticketreadstate',
|
|
constraint=models.UniqueConstraint(fields=('ticket', 'user'), name='unique_ticket_read_state'),
|
|
),
|
|
]
|