839 lines
62 KiB
Python
839 lines
62 KiB
Python
# Generated by Django 5.2.7 on 2025-12-11 11:55
|
|
|
|
import django.contrib.auth.models
|
|
import django.contrib.auth.validators
|
|
import django.core.validators
|
|
import django.db.models.deletion
|
|
import django.utils.timezone
|
|
import django_ckeditor_5.fields
|
|
import django_countries.fields
|
|
import django_extensions.db.fields
|
|
import recruitment.validators
|
|
import secured_fields.fields
|
|
from django.conf import settings
|
|
from django.db import migrations, models
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
initial = True
|
|
|
|
dependencies = [
|
|
('auth', '0012_alter_user_first_name_max_length'),
|
|
('contenttypes', '0002_remove_content_type_name'),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name='AgencyJobAssignment',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('max_candidates', models.PositiveIntegerField(help_text='Maximum candidates agency can submit for this job', verbose_name='Maximum Candidates')),
|
|
('candidates_submitted', models.PositiveIntegerField(default=0, help_text='Number of candidates submitted so far', verbose_name='Candidates Submitted')),
|
|
('assigned_date', models.DateTimeField(auto_now_add=True, verbose_name='Assigned Date')),
|
|
('deadline_date', models.DateTimeField(help_text='Deadline for agency to submit candidates', verbose_name='Deadline Date')),
|
|
('is_active', models.BooleanField(default=True, verbose_name='Is Active')),
|
|
('status', models.CharField(choices=[('ACTIVE', 'Active'), ('COMPLETED', 'Completed'), ('EXPIRED', 'Expired'), ('CANCELLED', 'Cancelled')], default='ACTIVE', max_length=20, verbose_name='Status')),
|
|
('deadline_extended', models.BooleanField(default=False, verbose_name='Deadline Extended')),
|
|
('original_deadline', models.DateTimeField(blank=True, help_text='Original deadline before extensions', null=True, verbose_name='Original Deadline')),
|
|
('admin_notes', models.TextField(blank=True, help_text='Internal notes about this assignment', verbose_name='Admin Notes')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Agency Job Assignment',
|
|
'verbose_name_plural': 'Agency Job Assignments',
|
|
'ordering': ['-created_at'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='BreakTime',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('start_time', models.TimeField(verbose_name='Start Time')),
|
|
('end_time', models.TimeField(verbose_name='End Time')),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='EmailContent',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('subject', models.CharField(max_length=255, verbose_name='Subject')),
|
|
('message', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Message Body')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Email Content',
|
|
'verbose_name_plural': 'Email Contents',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='FormStage',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('name', models.CharField(help_text='Name of the stage', max_length=200)),
|
|
('order', models.PositiveIntegerField(default=0, help_text='Order of the stage in the form')),
|
|
('is_predefined', models.BooleanField(default=False, help_text='Whether this is a default resume stage')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Form Stage',
|
|
'verbose_name_plural': 'Form Stages',
|
|
'ordering': ['order'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Interview',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('location_type', models.CharField(choices=[('Remote', 'Remote (e.g., Zoom, Google Meet)'), ('Onsite', 'In-Person (Physical Location)')], db_index=True, max_length=10, verbose_name='Location Type')),
|
|
('topic', models.CharField(blank=True, help_text="e.g., 'Zoom Topic: Software Interview' or 'Main Conference Room'", max_length=255, verbose_name='Meeting/Location Topic')),
|
|
('timezone', models.CharField(default='UTC', max_length=50, verbose_name='Timezone')),
|
|
('start_time', models.DateTimeField(db_index=True, verbose_name='Start Time')),
|
|
('duration', models.PositiveIntegerField(verbose_name='Duration (minutes)')),
|
|
('status', models.CharField(choices=[('waiting', 'Waiting'), ('started', 'Started'), ('ended', 'Ended'), ('cancelled', 'Cancelled')], db_index=True, default='waiting', max_length=20)),
|
|
('meeting_id', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='External Meeting ID')),
|
|
('password', models.CharField(blank=True, max_length=20, null=True)),
|
|
('zoom_gateway_response', models.JSONField(blank=True, null=True)),
|
|
('details_url', models.JSONField(blank=True, null=True)),
|
|
('participant_video', models.BooleanField(default=True)),
|
|
('join_before_host', models.BooleanField(default=False)),
|
|
('host_email', models.CharField(blank=True, max_length=255, null=True)),
|
|
('mute_upon_entry', models.BooleanField(default=False)),
|
|
('waiting_room', models.BooleanField(default=False)),
|
|
('physical_address', models.CharField(blank=True, max_length=255, null=True)),
|
|
('room_number', models.CharField(blank=True, max_length=50, null=True)),
|
|
],
|
|
options={
|
|
'verbose_name': 'Interview Location',
|
|
'verbose_name_plural': 'Interview Locations',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Participants',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Participant Name')),
|
|
('email', models.EmailField(max_length=254, verbose_name='Email')),
|
|
('phone', secured_fields.fields.EncryptedCharField(blank=True, max_length=12, null=True, verbose_name='Phone Number')),
|
|
('designation', models.CharField(blank=True, max_length=100, null=True, verbose_name='Designation')),
|
|
],
|
|
options={
|
|
'abstract': False,
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Settings',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('key', models.CharField(help_text='Unique key for the setting', max_length=100, unique=True, verbose_name='Setting Key')),
|
|
('value', models.TextField(help_text='Value for the setting', verbose_name='Setting Value')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Setting',
|
|
'verbose_name_plural': 'Settings',
|
|
'ordering': ['key'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Source',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('name', models.CharField(help_text='e.g., ATS, ERP ', max_length=100, unique=True, verbose_name='Source Name')),
|
|
('source_type', models.CharField(help_text='e.g., ATS, ERP ', max_length=100, verbose_name='Source Type')),
|
|
('description', models.TextField(blank=True, help_text='A description of the source', verbose_name='Description')),
|
|
('ip_address', models.GenericIPAddressField(blank=True, help_text='The IP address of the source', null=True, verbose_name='IP Address')),
|
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
('api_key', models.CharField(blank=True, help_text='API key for authentication (will be encrypted)', max_length=255, null=True, verbose_name='API Key')),
|
|
('api_secret', models.CharField(blank=True, help_text='API secret for authentication (will be encrypted)', max_length=255, null=True, verbose_name='API Secret')),
|
|
('trusted_ips', models.TextField(blank=True, help_text='Comma-separated list of trusted IP addresses', null=True, verbose_name='Trusted IP Addresses')),
|
|
('is_active', models.BooleanField(default=True, help_text='Whether this source is active for integration', verbose_name='Active')),
|
|
('integration_version', models.CharField(blank=True, help_text='Version of the integration protocol', max_length=50, verbose_name='Integration Version')),
|
|
('last_sync_at', models.DateTimeField(blank=True, help_text='Timestamp of the last successful synchronization', null=True, verbose_name='Last Sync At')),
|
|
('sync_status', models.CharField(blank=True, choices=[('IDLE', 'Idle'), ('SYNCING', 'Syncing'), ('SUCCESS', 'Success'), ('ERROR', 'Error'), ('DISABLED', 'Disabled')], default='IDLE', max_length=20, verbose_name='Sync Status')),
|
|
('sync_endpoint', models.URLField(blank=True, help_text='Endpoint URL for sending candidate data (for outbound sync)', null=True, verbose_name='Sync Endpoint')),
|
|
('sync_method', models.CharField(blank=True, choices=[('POST', 'POST'), ('PUT', 'PUT')], default='POST', help_text='HTTP method for outbound sync requests', max_length=10, verbose_name='Sync Method')),
|
|
('test_method', models.CharField(blank=True, choices=[('GET', 'GET'), ('POST', 'POST')], default='GET', help_text='HTTP method for connection testing', max_length=10, verbose_name='Test Method')),
|
|
('custom_headers', models.JSONField(blank=True, default=dict, help_text='JSON object with custom HTTP headers for sync requests', null=True, verbose_name='Custom Headers')),
|
|
('supports_outbound_sync', models.BooleanField(default=False, help_text='Whether this source supports receiving candidate data from ATS', verbose_name='Supports Outbound Sync')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Source',
|
|
'verbose_name_plural': 'Sources',
|
|
'ordering': ['name'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='CustomUser',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('password', models.CharField(max_length=128, verbose_name='password')),
|
|
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
|
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
|
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
|
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
|
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
|
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
|
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
|
('first_name', secured_fields.fields.EncryptedCharField(blank=True, max_length=150, verbose_name='first name')),
|
|
('user_type', models.CharField(choices=[('staff', 'Staff'), ('agency', 'Agency'), ('candidate', 'Candidate')], default='staff', max_length=20, verbose_name='User Type')),
|
|
('phone', secured_fields.fields.EncryptedCharField(blank=True, null=True, verbose_name='Phone')),
|
|
('profile_image', models.ImageField(blank=True, null=True, upload_to='profile_pic/', validators=[recruitment.validators.validate_image_size], verbose_name='Profile Image')),
|
|
('designation', models.CharField(blank=True, max_length=100, null=True, verbose_name='Designation')),
|
|
('email', models.EmailField(db_index=True, error_messages={'unique': 'A user with this email already exists.'}, max_length=254, unique=True)),
|
|
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
|
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
|
],
|
|
options={
|
|
'verbose_name': 'User',
|
|
'verbose_name_plural': 'Users',
|
|
},
|
|
managers=[
|
|
('objects', django.contrib.auth.models.UserManager()),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='AgencyAccessLink',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('unique_token', models.CharField(editable=False, max_length=64, unique=True, verbose_name='Unique Token')),
|
|
('access_password', models.CharField(help_text='Password for agency access', max_length=32, verbose_name='Access Password')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
|
|
('expires_at', models.DateTimeField(help_text='When this access link expires', verbose_name='Expires At')),
|
|
('last_accessed', models.DateTimeField(blank=True, null=True, verbose_name='Last Accessed')),
|
|
('access_count', models.PositiveIntegerField(default=0, verbose_name='Access Count')),
|
|
('is_active', models.BooleanField(default=True, verbose_name='Is Active')),
|
|
('assignment', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='access_link', to='recruitment.agencyjobassignment', verbose_name='Assignment')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Agency Access Link',
|
|
'verbose_name_plural': 'Agency Access Links',
|
|
'ordering': ['-created_at'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Document',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('object_id', models.PositiveIntegerField(db_index=True, verbose_name='Object ID')),
|
|
('file', models.FileField(upload_to='documents/%Y/%m/', validators=[recruitment.validators.validate_image_size], verbose_name='Document File')),
|
|
('document_type', models.CharField(choices=[('resume', 'Resume'), ('cover_letter', 'Cover Letter'), ('certificate', 'Certificate'), ('id_document', 'ID Document'), ('passport', 'Passport'), ('education', 'Education Document'), ('experience', 'Experience Letter'), ('other', 'Other')], db_index=True, default='other', max_length=20, verbose_name='Document Type')),
|
|
('description', models.CharField(blank=True, max_length=200, verbose_name='Description')),
|
|
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='Content Type')),
|
|
('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Uploaded By')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Document',
|
|
'verbose_name_plural': 'Documents',
|
|
'ordering': ['-created_at'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='FormField',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('label', models.CharField(help_text='Label for the field', max_length=200)),
|
|
('field_type', models.CharField(choices=[('text', 'Text Input'), ('email', 'Email'), ('phone', 'Phone'), ('textarea', 'Text Area'), ('file', 'File Upload'), ('date', 'Date Picker'), ('select', 'Dropdown'), ('radio', 'Radio Buttons'), ('checkbox', 'Checkboxes')], help_text='Type of the field', max_length=20)),
|
|
('placeholder', models.CharField(blank=True, help_text='Placeholder text', max_length=200)),
|
|
('required', models.BooleanField(default=False, help_text='Whether the field is required')),
|
|
('order', models.PositiveIntegerField(default=0, help_text='Order of the field in the stage')),
|
|
('is_predefined', models.BooleanField(default=False, help_text='Whether this is a default field')),
|
|
('options', models.JSONField(blank=True, default=list, help_text='Options for selection fields (stored as JSON array)')),
|
|
('file_types', models.CharField(blank=True, help_text="Allowed file types (comma-separated, e.g., '.pdf,.doc,.docx')", max_length=200)),
|
|
('max_file_size', models.PositiveIntegerField(default=5, help_text='Maximum file size in MB (default: 5MB)')),
|
|
('multiple_files', models.BooleanField(default=False, help_text='Allow multiple files to be uploaded')),
|
|
('max_files', models.PositiveIntegerField(default=1, help_text='Maximum number of files allowed (when multiple_files is True)')),
|
|
('is_required', models.BooleanField(default=False)),
|
|
('required_message', models.CharField(blank=True, max_length=255)),
|
|
('min_length', models.IntegerField(blank=True, null=True)),
|
|
('max_length', models.IntegerField(blank=True, null=True)),
|
|
('validation_pattern', models.CharField(blank=True, choices=[('', 'None'), ('email', 'Email'), ('phone', 'Phone'), ('url', 'URL'), ('number', 'Number'), ('alpha', 'Letters Only'), ('alphanum', 'Letters & Numbers'), ('custom', 'Custom')], max_length=50)),
|
|
('custom_pattern', models.CharField(blank=True, max_length=255)),
|
|
('min_value', models.CharField(blank=True, max_length=50)),
|
|
('max_value', models.CharField(blank=True, max_length=50)),
|
|
('min_file_size', models.FloatField(blank=True, null=True)),
|
|
('min_image_width', models.IntegerField(blank=True, null=True)),
|
|
('min_image_height', models.IntegerField(blank=True, null=True)),
|
|
('stage', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fields', to='recruitment.formstage')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Form Field',
|
|
'verbose_name_plural': 'Form Fields',
|
|
'ordering': ['order'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='FormSubmission',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('submitted_at', models.DateTimeField(auto_now_add=True, db_index=True)),
|
|
('applicant_name', models.CharField(blank=True, help_text='Name of the applicant', max_length=200)),
|
|
('applicant_email', models.EmailField(blank=True, db_index=True, help_text='Email of the applicant', max_length=254)),
|
|
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='form_submissions', to=settings.AUTH_USER_MODEL)),
|
|
],
|
|
options={
|
|
'verbose_name': 'Form Submission',
|
|
'verbose_name_plural': 'Form Submissions',
|
|
'ordering': ['-submitted_at'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='FieldResponse',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('value', models.JSONField(blank=True, help_text='Response value (stored as JSON)', null=True)),
|
|
('uploaded_file', models.FileField(blank=True, null=True, upload_to='form_uploads/')),
|
|
('field', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='recruitment.formfield')),
|
|
('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='recruitment.formsubmission')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Field Response',
|
|
'verbose_name_plural': 'Field Responses',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='FormTemplate',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('name', models.CharField(help_text='Name of the form template', max_length=200)),
|
|
('description', models.TextField(blank=True, help_text='Description of the form template')),
|
|
('is_active', models.BooleanField(default=False, help_text='Whether this template is active')),
|
|
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='form_templates', to=settings.AUTH_USER_MODEL)),
|
|
],
|
|
options={
|
|
'verbose_name': 'Form Template',
|
|
'verbose_name_plural': 'Form Templates',
|
|
'ordering': ['-created_at'],
|
|
},
|
|
),
|
|
migrations.AddField(
|
|
model_name='formsubmission',
|
|
name='template',
|
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', to='recruitment.formtemplate'),
|
|
),
|
|
migrations.AddField(
|
|
model_name='formstage',
|
|
name='template',
|
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stages', to='recruitment.formtemplate'),
|
|
),
|
|
migrations.CreateModel(
|
|
name='HiringAgency',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('name', models.CharField(max_length=200, unique=True, verbose_name='Agency Name')),
|
|
('contact_person', models.CharField(blank=True, max_length=150, verbose_name='Contact Person')),
|
|
('email', models.EmailField(max_length=254, unique=True)),
|
|
('phone', secured_fields.fields.EncryptedCharField(blank=True, max_length=20, null=True)),
|
|
('website', models.URLField(blank=True)),
|
|
('notes', models.TextField(blank=True, help_text='Internal notes about the agency')),
|
|
('country', django_countries.fields.CountryField(blank=True, max_length=2, null=True)),
|
|
('address', models.TextField(blank=True, null=True)),
|
|
('generated_password', models.CharField(blank=True, help_text='Generated password for agency user account', max_length=255, null=True)),
|
|
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='agency_profile', to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Hiring Agency',
|
|
'verbose_name_plural': 'Hiring Agencies',
|
|
'ordering': ['name'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Application',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('resume', models.FileField(upload_to='resumes/', verbose_name='Resume')),
|
|
('cover_letter', models.FileField(blank=True, null=True, upload_to='cover_letters/', verbose_name='Cover Letter')),
|
|
('is_resume_parsed', models.BooleanField(default=False, verbose_name='Resume Parsed')),
|
|
('parsed_summary', models.TextField(blank=True, verbose_name='Parsed Summary')),
|
|
('applied', models.BooleanField(default=False, verbose_name='Applied')),
|
|
('stage', models.CharField(choices=[('Applied', 'Applied'), ('Exam', 'Exam'), ('Interview', 'Interview'), ('Document Review', 'Document Review'), ('Offer', 'Offer'), ('Hired', 'Hired'), ('Rejected', 'Rejected')], db_index=True, default='Applied', max_length=20, verbose_name='Stage')),
|
|
('applicant_status', models.CharField(blank=True, choices=[('Applicant', 'Applicant'), ('Candidate', 'Candidate')], default='Applicant', max_length=20, null=True, verbose_name='Applicant Status')),
|
|
('exam_date', models.DateTimeField(blank=True, null=True, verbose_name='Exam Date')),
|
|
('exam_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Exam Status')),
|
|
('exam_score', models.FloatField(blank=True, null=True, verbose_name='Exam Score')),
|
|
('interview_date', models.DateTimeField(blank=True, null=True, verbose_name='Interview Date')),
|
|
('interview_status', models.CharField(blank=True, choices=[('Passed', 'Passed'), ('Failed', 'Failed')], max_length=20, null=True, verbose_name='Interview Status')),
|
|
('offer_date', models.DateField(blank=True, null=True, verbose_name='Offer Date')),
|
|
('offer_status', models.CharField(blank=True, choices=[('Accepted', 'Accepted'), ('Rejected', 'Rejected'), ('Pending', 'Pending')], max_length=20, null=True, verbose_name='Offer Status')),
|
|
('hired_date', models.DateField(blank=True, null=True, verbose_name='Hired Date')),
|
|
('join_date', models.DateField(blank=True, null=True, verbose_name='Join Date')),
|
|
('ai_analysis_data', models.JSONField(blank=True, default=dict, help_text='Full JSON output from the resume scoring model.', null=True, verbose_name='AI Analysis Data')),
|
|
('retry', models.SmallIntegerField(default=3, verbose_name='Resume Parsing Retry')),
|
|
('hiring_source', models.CharField(blank=True, choices=[('Public', 'Public'), ('Internal', 'Internal'), ('Agency', 'Agency')], default='Public', max_length=255, null=True, verbose_name='Hiring Source')),
|
|
('hiring_agency', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='applications', to='recruitment.hiringagency', verbose_name='Hiring Agency')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Application',
|
|
'verbose_name_plural': 'Applications',
|
|
},
|
|
),
|
|
migrations.AddField(
|
|
model_name='agencyjobassignment',
|
|
name='agency',
|
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='job_assignments', to='recruitment.hiringagency', verbose_name='Agency'),
|
|
),
|
|
migrations.CreateModel(
|
|
name='JobPosting',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('title', models.CharField(max_length=200)),
|
|
('department', models.CharField(blank=True, max_length=100)),
|
|
('job_type', models.CharField(choices=[('Full-time', 'Full-time'), ('Part-time', 'Part-time'), ('Contract', 'Contract'), ('Internship', 'Internship'), ('Faculty', 'Faculty'), ('Temporary', 'Temporary')], default='Full-time', max_length=20)),
|
|
('workplace_type', models.CharField(choices=[('On-site', 'On-site'), ('Remote', 'Remote'), ('Hybrid', 'Hybrid')], default='On-site', max_length=20)),
|
|
('location_city', models.CharField(blank=True, max_length=100)),
|
|
('location_state', models.CharField(blank=True, max_length=100)),
|
|
('location_country', models.CharField(default='Saudia Arabia', max_length=100)),
|
|
('description', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Description')),
|
|
('qualifications', django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True)),
|
|
('salary_range', models.CharField(blank=True, help_text='e.g., $60,000 - $80,000', max_length=200)),
|
|
('benefits', django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True)),
|
|
('application_url', models.URLField(blank=True, help_text='URL where applicants apply', null=True, validators=[django.core.validators.URLValidator()])),
|
|
('application_deadline', models.DateField(db_index=True)),
|
|
('application_instructions', django_ckeditor_5.fields.CKEditor5Field(blank=True, null=True)),
|
|
('internal_job_id', models.CharField(editable=False, max_length=50)),
|
|
('created_by', models.CharField(blank=True, help_text='Name of person who created this job', max_length=100)),
|
|
('status', models.CharField(choices=[('DRAFT', 'Draft'), ('ACTIVE', 'Active'), ('CLOSED', 'Closed'), ('CANCELLED', 'Cancelled'), ('ARCHIVED', 'Archived')], db_index=True, default='DRAFT', max_length=20)),
|
|
('hash_tags', models.CharField(blank=True, help_text='Comma-separated hashtags for linkedin post like #hiring,#jobopening', max_length=200, validators=[recruitment.validators.validate_hash_tags])),
|
|
('linkedin_post_id', models.CharField(blank=True, help_text='LinkedIn post ID after posting', max_length=200)),
|
|
('linkedin_post_url', models.URLField(blank=True, help_text='Direct URL to LinkedIn post')),
|
|
('posted_to_linkedin', models.BooleanField(default=False)),
|
|
('linkedin_post_status', models.CharField(blank=True, help_text='Status of LinkedIn posting', max_length=50)),
|
|
('linkedin_posted_at', models.DateTimeField(blank=True, null=True)),
|
|
('linkedin_post_formated_data', models.TextField(blank=True, null=True)),
|
|
('published_at', models.DateTimeField(blank=True, db_index=True, null=True)),
|
|
('position_number', models.CharField(blank=True, help_text='University position number', max_length=50)),
|
|
('reporting_to', models.CharField(blank=True, help_text='Who this position reports to', max_length=100)),
|
|
('open_positions', models.PositiveIntegerField(default=1, help_text='Number of open positions for this job')),
|
|
('max_applications', models.PositiveIntegerField(blank=True, default=1000, help_text='Maximum number of applications allowed', null=True)),
|
|
('cancel_reason', models.TextField(blank=True, help_text='Reason for canceling the job posting', verbose_name='Cancel Reason')),
|
|
('cancelled_by', models.CharField(blank=True, help_text='Name of person who cancelled this job', max_length=100, verbose_name='Cancelled By')),
|
|
('cancelled_at', models.DateTimeField(blank=True, null=True)),
|
|
('ai_parsed', models.BooleanField(default=False, help_text='Whether the job posting has been parsed by AI', verbose_name='AI Parsed')),
|
|
('cv_zip_file', models.FileField(blank=True, null=True, upload_to='job_zips/')),
|
|
('zip_created', models.BooleanField(default=False)),
|
|
('assigned_to', models.ForeignKey(blank=True, help_text='The user who has been assigned to this job', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_jobs', to=settings.AUTH_USER_MODEL, verbose_name='Assigned To')),
|
|
('hiring_agency', models.ManyToManyField(blank=True, help_text='External agency responsible for sourcing applicants for this role', related_name='jobs', to='recruitment.hiringagency', verbose_name='Hiring Agency')),
|
|
('source', models.ForeignKey(blank=True, help_text='The system or channel from which this job posting originated or was first published.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='job_postings', to='recruitment.source')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Job Posting',
|
|
'verbose_name_plural': 'Job Postings',
|
|
'ordering': ['-created_at'],
|
|
},
|
|
),
|
|
migrations.AddField(
|
|
model_name='formtemplate',
|
|
name='job',
|
|
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='form_template', to='recruitment.jobposting'),
|
|
),
|
|
migrations.CreateModel(
|
|
name='BulkInterviewTemplate',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('start_date', models.DateField(db_index=True, verbose_name='Start Date')),
|
|
('end_date', models.DateField(db_index=True, verbose_name='End Date')),
|
|
('working_days', models.JSONField(verbose_name='Working Days')),
|
|
('topic', models.CharField(max_length=255, verbose_name='Interview Topic')),
|
|
('start_time', models.TimeField(verbose_name='Start Time')),
|
|
('end_time', models.TimeField(verbose_name='End Time')),
|
|
('break_start_time', models.TimeField(blank=True, null=True, verbose_name='Break Start Time')),
|
|
('break_end_time', models.TimeField(blank=True, null=True, verbose_name='Break End Time')),
|
|
('interview_duration', models.PositiveIntegerField(verbose_name='Interview Duration (minutes)')),
|
|
('buffer_time', models.PositiveIntegerField(default=0, verbose_name='Buffer Time (minutes)')),
|
|
('schedule_interview_type', models.CharField(choices=[('Remote', 'Remote (e.g., Zoom)'), ('Onsite', 'In-Person (Physical Location)')], default='Onsite', max_length=10, verbose_name='Interview Type')),
|
|
('physical_address', models.CharField(blank=True, max_length=255, null=True)),
|
|
('applications', models.ManyToManyField(blank=True, related_name='interview_schedules', to='recruitment.application')),
|
|
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
|
('interview', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='schedule_templates', to='recruitment.interview', verbose_name='Location Template (Zoom/Onsite)')),
|
|
('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interview_schedules', to='recruitment.jobposting')),
|
|
],
|
|
options={
|
|
'abstract': False,
|
|
},
|
|
),
|
|
migrations.AddField(
|
|
model_name='application',
|
|
name='job',
|
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applications', to='recruitment.jobposting', verbose_name='Job'),
|
|
),
|
|
migrations.AddField(
|
|
model_name='agencyjobassignment',
|
|
name='job',
|
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='agency_assignments', to='recruitment.jobposting', verbose_name='Job'),
|
|
),
|
|
migrations.CreateModel(
|
|
name='JobPostingImage',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('post_image', models.ImageField(upload_to='post/', validators=[recruitment.validators.validate_image_size])),
|
|
('job', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='post_images', to='recruitment.jobposting')),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='Message',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('subject', models.CharField(max_length=200, verbose_name='Subject')),
|
|
('content', models.TextField(verbose_name='Message Content')),
|
|
('message_type', models.CharField(choices=[('direct', 'Direct Message'), ('job_related', 'Job Related'), ('system', 'System Notification')], default='direct', max_length=20, verbose_name='Message Type')),
|
|
('is_read', models.BooleanField(default=False, verbose_name='Is Read')),
|
|
('read_at', models.DateTimeField(blank=True, null=True, verbose_name='Read At')),
|
|
('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='recruitment.jobposting', verbose_name='Related Job')),
|
|
('recipient', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='received_messages', to=settings.AUTH_USER_MODEL, verbose_name='Recipient')),
|
|
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL, verbose_name='Sender')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Message',
|
|
'verbose_name_plural': 'Messages',
|
|
'ordering': ['-created_at'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Note',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('note_type', models.CharField(choices=[('Feedback', 'Candidate Feedback'), ('Logistics', 'Logistical Note'), ('General', 'General Comment')], default='Feedback', max_length=50, verbose_name='Note Type')),
|
|
('content', django_ckeditor_5.fields.CKEditor5Field(verbose_name='Content/Feedback')),
|
|
('application', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='recruitment.application', verbose_name='Application')),
|
|
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interview_notes', to=settings.AUTH_USER_MODEL, verbose_name='Author')),
|
|
('interview', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='recruitment.interview', verbose_name='Scheduled Interview')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Interview Note',
|
|
'verbose_name_plural': 'Interview Notes',
|
|
'ordering': ['created_at'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Notification',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('message', models.TextField(verbose_name='Notification Message')),
|
|
('notification_type', models.CharField(choices=[('email', 'Email'), ('in_app', 'In-App')], default='email', max_length=20, verbose_name='Notification Type')),
|
|
('status', models.CharField(choices=[('pending', 'Pending'), ('sent', 'Sent'), ('read', 'Read'), ('failed', 'Failed'), ('retrying', 'Retrying')], default='pending', max_length=20, verbose_name='Status')),
|
|
('scheduled_for', models.DateTimeField(help_text='The date and time this notification is scheduled to be sent.', verbose_name='Scheduled Send Time')),
|
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
('updated_at', models.DateTimeField(auto_now=True)),
|
|
('attempts', models.PositiveIntegerField(default=0, verbose_name='Send Attempts')),
|
|
('last_error', models.TextField(blank=True, verbose_name='Last Error Message')),
|
|
('recipient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL, verbose_name='Recipient')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Notification',
|
|
'verbose_name_plural': 'Notifications',
|
|
'ordering': ['-scheduled_for', '-created_at'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Person',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('first_name', secured_fields.fields.EncryptedCharField(max_length=255, verbose_name='First Name')),
|
|
('last_name', models.CharField(max_length=255, verbose_name='Last Name')),
|
|
('middle_name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Middle Name')),
|
|
('email', models.EmailField(db_index=True, max_length=254, unique=True, verbose_name='Email')),
|
|
('phone', secured_fields.fields.EncryptedCharField(blank=True, null=True, verbose_name='Phone')),
|
|
('date_of_birth', models.DateField(blank=True, null=True, verbose_name='Date of Birth')),
|
|
('gender', models.CharField(blank=True, choices=[('M', 'Male'), ('F', 'Female')], max_length=1, null=True, verbose_name='Gender')),
|
|
('gpa', models.DecimalField(decimal_places=2, help_text='GPA must be between 0 and 4.', max_digits=3, verbose_name='GPA')),
|
|
('national_id', secured_fields.fields.EncryptedCharField(help_text='Enter the national id or iqama number')),
|
|
('nationality', django_countries.fields.CountryField(blank=True, max_length=2, null=True, verbose_name='Nationality')),
|
|
('address', models.TextField(blank=True, null=True, verbose_name='Address')),
|
|
('profile_image', models.ImageField(blank=True, null=True, upload_to='profile_pic/', validators=[recruitment.validators.validate_image_size], verbose_name='Profile Image')),
|
|
('linkedin_profile', models.URLField(blank=True, null=True, verbose_name='LinkedIn Profile URL')),
|
|
('agency', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='recruitment.hiringagency', verbose_name='Hiring Agency')),
|
|
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='person_profile', to=settings.AUTH_USER_MODEL, verbose_name='User Account')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Person',
|
|
'verbose_name_plural': 'People',
|
|
},
|
|
),
|
|
migrations.AddField(
|
|
model_name='application',
|
|
name='person',
|
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applications', to='recruitment.person', verbose_name='Person'),
|
|
),
|
|
migrations.CreateModel(
|
|
name='ScheduledInterview',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('cancelled_at', models.DateTimeField(blank=True, null=True, verbose_name='Cancelled At')),
|
|
('cancelled_reason', models.TextField(blank=True, null=True, verbose_name='Cancellation Reason')),
|
|
('interview_date', models.DateField(db_index=True, verbose_name='Interview Date')),
|
|
('interview_time', models.TimeField(verbose_name='Interview Time')),
|
|
('interview_type', models.CharField(choices=[('Remote', 'Remote (e.g., Zoom, Google Meet)'), ('Onsite', 'In-Person (Physical Location)')], default='Remote', max_length=20)),
|
|
('status', models.CharField(choices=[('scheduled', 'Scheduled'), ('confirmed', 'Confirmed'), ('cancelled', 'Cancelled'), ('completed', 'Completed')], db_index=True, default='scheduled', max_length=20)),
|
|
('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interviews', to='recruitment.application')),
|
|
('interview', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interview', to='recruitment.interview', verbose_name='Interview/Meeting')),
|
|
('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scheduled_interviews', to='recruitment.jobposting')),
|
|
('participants', models.ManyToManyField(blank=True, to='recruitment.participants')),
|
|
('schedule', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interviews', to='recruitment.bulkinterviewtemplate')),
|
|
('system_users', models.ManyToManyField(blank=True, related_name='attended_interviews', to=settings.AUTH_USER_MODEL)),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='SharedFormTemplate',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('is_public', models.BooleanField(default=False, help_text='Whether this template is publicly available')),
|
|
('shared_with', models.ManyToManyField(blank=True, related_name='shared_templates', to=settings.AUTH_USER_MODEL)),
|
|
('template', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='recruitment.formtemplate')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Shared Form Template',
|
|
'verbose_name_plural': 'Shared Form Templates',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='IntegrationLog',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
|
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
|
|
('slug', django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug')),
|
|
('action', models.CharField(choices=[('REQUEST', 'Request'), ('RESPONSE', 'Response'), ('ERROR', 'Error'), ('SYNC', 'Sync'), ('CREATE_JOB', 'Create Job'), ('UPDATE_JOB', 'Update Job')], max_length=20, verbose_name='Action')),
|
|
('endpoint', models.CharField(blank=True, max_length=255, verbose_name='Endpoint')),
|
|
('method', models.CharField(blank=True, max_length=50, verbose_name='HTTP Method')),
|
|
('request_data', models.JSONField(blank=True, null=True, verbose_name='Request Data')),
|
|
('response_data', models.JSONField(blank=True, null=True, verbose_name='Response Data')),
|
|
('status_code', models.CharField(blank=True, max_length=10, verbose_name='Status Code')),
|
|
('error_message', models.TextField(blank=True, verbose_name='Error Message')),
|
|
('ip_address', models.GenericIPAddressField(verbose_name='IP Address')),
|
|
('user_agent', models.CharField(blank=True, max_length=255, verbose_name='User Agent')),
|
|
('processing_time', models.FloatField(blank=True, null=True, verbose_name='Processing Time (seconds)')),
|
|
('source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='integration_logs', to='recruitment.source', verbose_name='Source')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Integration Log',
|
|
'verbose_name_plural': 'Integration Logs',
|
|
'ordering': ['-created_at'],
|
|
},
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='customuser',
|
|
index=models.Index(fields=['user_type', 'is_active'], name='recruitment_user_ty_ba71c7_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='customuser',
|
|
index=models.Index(fields=['email'], name='recruitment_email_9f8255_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='agencyaccesslink',
|
|
index=models.Index(fields=['unique_token'], name='recruitment_unique__f91e76_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='agencyaccesslink',
|
|
index=models.Index(fields=['expires_at'], name='recruitment_expires_954ed9_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='agencyaccesslink',
|
|
index=models.Index(fields=['is_active'], name='recruitment_is_acti_4b0804_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='document',
|
|
index=models.Index(fields=['content_type', 'object_id', 'document_type', 'created_at'], name='recruitment_content_547650_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='document',
|
|
index=models.Index(fields=['document_type', 'created_at'], name='recruitment_documen_137905_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='document',
|
|
index=models.Index(fields=['uploaded_by', 'created_at'], name='recruitment_uploade_a50157_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='fieldresponse',
|
|
index=models.Index(fields=['submission'], name='recruitment_submiss_474130_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='fieldresponse',
|
|
index=models.Index(fields=['field'], name='recruitment_field_i_097e5b_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='formsubmission',
|
|
index=models.Index(fields=['submitted_at'], name='recruitment_submitt_7946c8_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='formtemplate',
|
|
index=models.Index(fields=['created_at'], name='recruitment_created_c21775_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='formtemplate',
|
|
index=models.Index(fields=['is_active'], name='recruitment_is_acti_ae5efb_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='agencyjobassignment',
|
|
index=models.Index(fields=['agency', 'status'], name='recruitment_agency__491a54_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='agencyjobassignment',
|
|
index=models.Index(fields=['job', 'status'], name='recruitment_job_id_d798a8_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='agencyjobassignment',
|
|
index=models.Index(fields=['deadline_date'], name='recruitment_deadlin_57d3b4_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='agencyjobassignment',
|
|
index=models.Index(fields=['is_active'], name='recruitment_is_acti_93b919_idx'),
|
|
),
|
|
migrations.AlterUniqueTogether(
|
|
name='agencyjobassignment',
|
|
unique_together={('agency', 'job')},
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='message',
|
|
index=models.Index(fields=['sender', 'created_at'], name='recruitment_sender__49d984_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='message',
|
|
index=models.Index(fields=['recipient', 'is_read', 'created_at'], name='recruitment_recipie_af0e6d_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='message',
|
|
index=models.Index(fields=['job', 'created_at'], name='recruitment_job_id_18f813_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='message',
|
|
index=models.Index(fields=['message_type', 'created_at'], name='recruitment_message_f25659_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='notification',
|
|
index=models.Index(fields=['status', 'scheduled_for'], name='recruitment_status_0ebbe4_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='notification',
|
|
index=models.Index(fields=['recipient'], name='recruitment_recipie_eadf4c_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='person',
|
|
index=models.Index(fields=['email'], name='recruitment_email_0b1ab1_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='person',
|
|
index=models.Index(fields=['first_name', 'last_name'], name='recruitment_first_n_739de5_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='person',
|
|
index=models.Index(fields=['created_at'], name='recruitment_created_33495a_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='person',
|
|
index=models.Index(fields=['agency', 'created_at'], name='recruitment_agency__0b6915_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='application',
|
|
index=models.Index(fields=['person', 'job'], name='recruitment_person__34355c_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='application',
|
|
index=models.Index(fields=['stage'], name='recruitment_stage_52c2d1_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='application',
|
|
index=models.Index(fields=['created_at'], name='recruitment_created_80633f_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='application',
|
|
index=models.Index(fields=['person', 'stage', 'created_at'], name='recruitment_person__8715ec_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='application',
|
|
index=models.Index(fields=['job', 'stage', 'created_at'], name='recruitment_job_id_f59875_idx'),
|
|
),
|
|
migrations.AlterUniqueTogether(
|
|
name='application',
|
|
unique_together={('person', 'job')},
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='scheduledinterview',
|
|
index=models.Index(fields=['job', 'status'], name='recruitment_job_id_f09e22_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='scheduledinterview',
|
|
index=models.Index(fields=['interview_date', 'interview_time'], name='recruitment_intervi_7f5877_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='scheduledinterview',
|
|
index=models.Index(fields=['application', 'job'], name='recruitment_applica_927561_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='jobposting',
|
|
index=models.Index(fields=['status', 'created_at', 'title'], name='recruitment_status_8b77aa_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='jobposting',
|
|
index=models.Index(fields=['slug'], name='recruitment_slug_004045_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='jobposting',
|
|
index=models.Index(fields=['assigned_to', 'status'], name='recruitment_assigne_60538f_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='jobposting',
|
|
index=models.Index(fields=['application_deadline', 'status'], name='recruitment_applica_206cb4_idx'),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name='jobposting',
|
|
index=models.Index(fields=['created_by', 'created_at'], name='recruitment_created_1e78e2_idx'),
|
|
),
|
|
]
|