chore: initial snapshot of tubco people portal

This commit is contained in:
Md Bayazid Bostame
2026-03-19 10:22:20 +01:00
commit 9fe3c2ea82
81 changed files with 8698 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name='EmployeeProfile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('full_name', models.CharField(max_length=255)),
('first_name', models.CharField(max_length=100)),
('last_name', models.CharField(max_length=155)),
('department', models.CharField(blank=True, max_length=255)),
('job_title', models.CharField(blank=True, max_length=255)),
('work_email', models.EmailField(max_length=254, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='OnboardingRequest',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('full_name', models.CharField(max_length=255, verbose_name='Vorname und Nachname')),
('job_title', models.CharField(blank=True, max_length=255, verbose_name='Berufsbezeichnung')),
('department', models.CharField(blank=True, max_length=255, verbose_name='Abteilung')),
('work_email', models.EmailField(max_length=254, verbose_name='Gewünschte dienstliche E-Mail-Adresse')),
('contract_start', models.DateField(verbose_name='Vertragsbeginn')),
('handover_date', models.DateField(blank=True, null=True, verbose_name='Gewünschtes Übergabedatum der Geräte')),
('group_mailboxes_required', models.BooleanField(default=False, verbose_name='Gruppenpostfächer erforderlich?')),
('group_mailboxes', models.TextField(blank=True, verbose_name='Gruppenpostfächer')),
('needed_devices', models.TextField(blank=True, verbose_name='Benötigte Geräte und Gegenstände')),
('needed_software', models.TextField(blank=True, verbose_name='Benötigte Software')),
('needed_accesses', models.TextField(blank=True, verbose_name='Benötigte Zugänge')),
('needed_workspace_groups', models.TextField(blank=True, verbose_name='Benötigte Gruppen im Workspace')),
('additional_software_needed', models.BooleanField(default=False, verbose_name='Wird zusätzliche Software benötigt?')),
('additional_software', models.TextField(blank=True, verbose_name='Zusätzlich gewünschte Software (ohne Garantie)')),
('needed_resources', models.TextField(blank=True, verbose_name='Benötigte Ressourcen')),
('phone_number', models.CharField(blank=True, max_length=100, verbose_name='TUBS-Telefon-Direktwahl-Nr. 030 447202 (10-89)')),
('additional_notes', models.TextField(blank=True, verbose_name='Raum für zusätzliche Anmerkungen und Wünsche')),
('agreement', models.TextField(blank=True, verbose_name='Vereinbarung')),
('signature_url', models.URLField(blank=True, verbose_name='Unterschrift')),
('personalized_text', models.TextField(blank=True, help_text='Optionaler individueller Textblock im Onboarding PDF.', verbose_name='Personalisierter Text für PDF')),
('generated_pdf_path', models.CharField(blank=True, max_length=500)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
),
]

View File

@@ -0,0 +1,91 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='onboardingrequest',
name='additional_access_needed',
field=models.BooleanField(default=False, verbose_name='Werden weitere Zugänge benötigt?'),
),
migrations.AddField(
model_name='onboardingrequest',
name='additional_access_text',
field=models.TextField(blank=True, verbose_name='Weitere Zugänge (Freitext)'),
),
migrations.AddField(
model_name='onboardingrequest',
name='additional_hardware',
field=models.TextField(blank=True, verbose_name='Zusätzliche Hardware'),
),
migrations.AddField(
model_name='onboardingrequest',
name='additional_hardware_needed',
field=models.BooleanField(default=False, verbose_name='Wird zusätzliche Hardware benötigt?'),
),
migrations.AddField(
model_name='onboardingrequest',
name='additional_hardware_other',
field=models.TextField(blank=True, verbose_name='Weitere Hardware (Freitext)'),
),
migrations.AddField(
model_name='onboardingrequest',
name='business_card_email',
field=models.EmailField(blank=True, max_length=254, verbose_name='E-Mailadresse (Visitenkarte)'),
),
migrations.AddField(
model_name='onboardingrequest',
name='business_card_name',
field=models.CharField(blank=True, max_length=255, verbose_name='Name (Visitenkarte)'),
),
migrations.AddField(
model_name='onboardingrequest',
name='business_card_phone',
field=models.CharField(blank=True, max_length=100, verbose_name='Telefonnummer (Visitenkarte)'),
),
migrations.AddField(
model_name='onboardingrequest',
name='business_card_title',
field=models.CharField(blank=True, max_length=255, verbose_name='Titel (Visitenkarte)'),
),
migrations.AddField(
model_name='onboardingrequest',
name='employment_end_date',
field=models.DateField(blank=True, null=True, verbose_name='Enddatum (nur bei befristet)'),
),
migrations.AddField(
model_name='onboardingrequest',
name='employment_type',
field=models.CharField(blank=True, choices=[('befristet', 'befristet'), ('unbefristet', 'unbefristet')], max_length=20, verbose_name='Beschäftigungsverhältnis'),
),
migrations.AddField(
model_name='onboardingrequest',
name='inherit_phone_number',
field=models.BooleanField(default=False, verbose_name='Telefonnummer von Vorgängerperson übernehmen'),
),
migrations.AddField(
model_name='onboardingrequest',
name='order_business_cards',
field=models.BooleanField(default=False, verbose_name='Bestellung Visitenkarten'),
),
migrations.AddField(
model_name='onboardingrequest',
name='successor_name',
field=models.CharField(blank=True, max_length=255, verbose_name='Name der Vorgängerperson'),
),
migrations.AddField(
model_name='onboardingrequest',
name='successor_required',
field=models.BooleanField(default=False, verbose_name='Neue Mitarbeitende ist Nachfolge von?'),
),
migrations.AlterField(
model_name='onboardingrequest',
name='phone_number',
field=models.CharField(blank=True, max_length=100, verbose_name='TUB/CO-Telefon-Direktwahl-Nr. 030 447202 (10-89)'),
),
]

View File

@@ -0,0 +1,21 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0002_form_updates'),
]
operations = [
migrations.AddField(
model_name='onboardingrequest',
name='gender',
field=models.CharField(blank=True, choices=[('frau', 'Frau'), ('herr', 'Herr'), ('divers', 'Divers')], max_length=20, verbose_name='Geschlecht'),
),
migrations.AddField(
model_name='onboardingrequest',
name='onboarded_by_email',
field=models.EmailField(blank=True, max_length=254, verbose_name='E-Mail der anfordernden Person'),
),
]

View File

@@ -0,0 +1,43 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0003_gender_onboarded_by'),
]
operations = [
migrations.CreateModel(
name='WorkflowConfig',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(default='Default', max_length=120, unique=True)),
('it_onboarding_email', models.EmailField(blank=True, max_length=254)),
('general_info_email', models.EmailField(blank=True, max_length=254)),
('business_card_email', models.EmailField(blank=True, max_length=254)),
('hr_works_email', models.EmailField(blank=True, max_length=254)),
('legal_text', models.TextField(blank=True, default='Eine Ausrüstungsvereinbarung erlaubt es einem Mitarbeitenden, die Ausrüstung des Unternehmens im Außendienst oder zu Hause zu nutzen und mitzunehmen.')),
],
),
migrations.CreateModel(
name='FormOption',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('category', models.CharField(choices=[('department', 'Abteilung'), ('device', 'Geräte'), ('software', 'Software'), ('access', 'Zugänge'), ('workspace_group', 'Workspace-Gruppen'), ('resource', 'Ressourcen'), ('phone', 'Telefonnummern')], max_length=40)),
('label', models.CharField(max_length=255)),
('value', models.CharField(blank=True, max_length=255)),
('sort_order', models.PositiveIntegerField(default=0)),
('is_active', models.BooleanField(default=True)),
],
options={
'ordering': ['category', 'sort_order', 'label'],
'unique_together': {('category', 'label')},
},
),
migrations.AlterField(
model_name='onboardingrequest',
name='gender',
field=models.CharField(blank=True, choices=[('herr', 'Herr'), ('frau', 'Frau'), ('divers', 'Divers')], max_length=20, verbose_name='Anrede'),
),
]

View File

@@ -0,0 +1,68 @@
from django.db import migrations
def seed_defaults(apps, schema_editor):
FormOption = apps.get_model('workflows', 'FormOption')
WorkflowConfig = apps.get_model('workflows', 'WorkflowConfig')
option_map = {
'department': [
'Buchhaltung/Personalverwaltung', 'IT-Service', 'Azubi', 'Marketing/Kommunikation', 'Messe',
'Kongresse', 'TNB/Studiengänge', 'TUB-Academy', 'Projekte TUB', 'TU Berlin Summer + Winter School',
],
'device': [
'Laptop', 'Docking-Station', 'Tastatur und Maus', 'Kopfhörer', 'Tragetasche', 'Monitor', 'Schlüssel', 'Tischtelefon',
],
'software': [
'eM Client', 'KeepassXC', 'Nextcloud', '7-Zip', 'PDF Reader', 'PDF-Editor (Flexi PDF)',
'Firefox', 'Chrome', 'Backup Client', 'MS Office', 'Zoom', 'Cisco VPN Client',
],
'access': ['TU Konto', 'HR Works', 'Datev', 'Odoo'],
'workspace_group': [
'Group-Academy', 'Group-BuSu', 'Group-EIT-Urban-Mobility', 'Group-EL', 'Group-EM', 'Group-IT-Services',
'Group-Kongresse-Events', 'Group-MaCo', 'Group-Messe', 'Group-Messe-Kongresse', 'Group-MSE', 'Group-SuMo',
'Group-TNB', 'Group-TUBS', 'Group-Wima', 'Group-Leitungsrunde', 'Campus-Euref', 'Group-Lohnbuchhaltung',
'Group-SU-WU', 'NWM',
],
'resource': ['Drucker HBS 5./6. OG', 'Drucker Euref'],
'phone': [
'030 4472021 (0-9)', '030 4472022 (0-9)', '030 4472023 (0-9)', '030 4472024 (0-9)',
'030 4472025 (0-9)', '030 4472026 (0-9)', '030 4472027 (0-9)', '030 4472028 (0-9)',
],
}
for category, labels in option_map.items():
for idx, label in enumerate(labels, start=1):
FormOption.objects.get_or_create(
category=category,
label=label,
defaults={'value': label, 'sort_order': idx, 'is_active': True},
)
WorkflowConfig.objects.get_or_create(
name='Default',
defaults={
'it_onboarding_email': 'it@tub.co',
'general_info_email': 'ingo.einacker@tub.co',
'business_card_email': 'kommunikation@tub.co',
'hr_works_email': 'dittrich@tub.co',
},
)
def rollback_seed(apps, schema_editor):
FormOption = apps.get_model('workflows', 'FormOption')
WorkflowConfig = apps.get_model('workflows', 'WorkflowConfig')
FormOption.objects.all().delete()
WorkflowConfig.objects.filter(name='Default').delete()
class Migration(migrations.Migration):
dependencies = [
('workflows', '0004_backend_config_models'),
]
operations = [
migrations.RunPython(seed_defaults, rollback_seed),
]

View File

@@ -0,0 +1,33 @@
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('workflows', '0005_seed_backend_config'),
]
operations = [
migrations.AddField(
model_name='workflowconfig',
name='key_notification_email',
field=models.EmailField(blank=True, max_length=254),
),
migrations.CreateModel(
name='OffboardingRequest',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('full_name', models.CharField(max_length=255, verbose_name='Vorname und Nachname')),
('work_email', models.EmailField(max_length=254, verbose_name='Dienstliche E-Mail-Adresse')),
('department', models.CharField(blank=True, max_length=255, verbose_name='Abteilung')),
('job_title', models.CharField(blank=True, max_length=255, verbose_name='Berufsbezeichnung')),
('last_working_day', models.DateField(verbose_name='Letzter Arbeitstag')),
('offboarding_reason', models.TextField(blank=True, verbose_name='Grund')),
('notes', models.TextField(blank=True, verbose_name='Notizen')),
('requested_by_email', models.EmailField(max_length=254, verbose_name='E-Mail der anfordernden Person')),
('created_at', models.DateTimeField(auto_now_add=True)),
('employee_profile', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='workflows.employeeprofile')),
],
),
]

View File

@@ -0,0 +1,20 @@
from django.db import migrations
def seed_key_email(apps, schema_editor):
WorkflowConfig = apps.get_model('workflows', 'WorkflowConfig')
for cfg in WorkflowConfig.objects.all():
if not cfg.key_notification_email:
cfg.key_notification_email = 'minuth@tub.co'
cfg.save(update_fields=['key_notification_email'])
class Migration(migrations.Migration):
dependencies = [
('workflows', '0006_offboarding_and_key_email'),
]
operations = [
migrations.RunPython(seed_key_email, migrations.RunPython.noop),
]

View File

@@ -0,0 +1,16 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0007_seed_key_email'),
]
operations = [
migrations.AddField(
model_name='offboardingrequest',
name='generated_pdf_path',
field=models.CharField(blank=True, max_length=500),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.5 on 2026-03-09 12:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0008_offboarding_pdf_path'),
]
operations = [
migrations.AddField(
model_name='offboardingrequest',
name='signature',
field=models.CharField(blank=True, max_length=255, verbose_name='Unterschrift (Name)'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.5 on 2026-03-09 13:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0009_offboardingrequest_signature'),
]
operations = [
migrations.AddField(
model_name='onboardingrequest',
name='signature_image',
field=models.ImageField(blank=True, null=True, upload_to='signatures/', verbose_name='Unterschrift (Bilddatei)'),
),
]

View File

@@ -0,0 +1,27 @@
# Generated by Django 5.1.5 on 2026-03-09 14:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0010_onboardingrequest_signature_image'),
]
operations = [
migrations.CreateModel(
name='NotificationTemplate',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(choices=[('onboarding_it', 'Onboarding: IT'), ('onboarding_general_info', 'Onboarding: Allgemeine Info'), ('onboarding_business_card', 'Onboarding: Visitenkarte'), ('onboarding_hr_works', 'Onboarding: HR Works'), ('onboarding_key', 'Onboarding: Schlüssel'), ('onboarding_reference', 'Onboarding: Referenz Anfordernde Person'), ('offboarding_it', 'Offboarding: IT'), ('offboarding_general_info', 'Offboarding: Allgemeine Info'), ('offboarding_hr_works_disable', 'Offboarding: HR Works Deaktivierung'), ('offboarding_reference', 'Offboarding: Referenz Anfordernde Person')], max_length=60, unique=True)),
('subject_template', models.CharField(max_length=255)),
('body_template', models.TextField()),
('is_active', models.BooleanField(default=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
options={
'ordering': ['key'],
},
),
]

View File

@@ -0,0 +1,72 @@
from django.db import migrations
def seed_notification_templates(apps, schema_editor):
NotificationTemplate = apps.get_model('workflows', 'NotificationTemplate')
templates = {
'onboarding_it': {
'subject_template': '[Onboarding] {{ FULL_NAME }} | Anfrage von {{ REQUESTED_BY }}',
'body_template': 'Neue Onboarding-Anfrage für {{ FULL_NAME }}.\nAbteilung: {{ DEPARTMENT }}\nVertragsbeginn: {{ CONTRACT_START }}\nAngefordert von: {{ REQUESTED_BY }}\nBitte IT-Setup vorbereiten.',
},
'onboarding_general_info': {
'subject_template': '[Info Onboarding] {{ FULL_NAME }} | Anfrage von {{ REQUESTED_BY }}',
'body_template': 'Hallo,\n\n{{ FULL_NAME }} wird onboarded.\nAbteilung: {{ DEPARTMENT }}\nVertragsbeginn: {{ CONTRACT_START }}\nAngefordert von: {{ REQUESTED_BY }}\n',
},
'onboarding_business_card': {
'subject_template': '[Visitenkarte] {{ FULL_NAME }} | Anfrage von {{ REQUESTED_BY }}',
'body_template': 'Hallo,\n\nbitte Visitenkarten erstellen:\nName: {{ BUSINESS_CARD_NAME }}\nTitel: {{ BUSINESS_CARD_TITLE }}\nE-Mail: {{ BUSINESS_CARD_EMAIL }}\nTelefon: {{ BUSINESS_CARD_PHONE }}\nAngefordert von: {{ REQUESTED_BY }}\n',
},
'onboarding_hr_works': {
'subject_template': '[HR Works] {{ FULL_NAME }} | Anfrage von {{ REQUESTED_BY }}',
'body_template': 'Hello Stefanie,\n\nEs ist wieder soweit. Zuwachs!\n\nKönntest du deshalb bitte ein HR Works Konto mit den folgenden Daten erstellen:\n\nName: {{ VORNAME }} {{ NACHNAME }}\nAbteilung: {{ DEPARTMENT }}\nVertragsbeginn: {{ CONTRACT_START }}\nE-Mail-Adresse: {{ EMAIL }}\n\n{% if PDF_LINK %}In 2 Minuten findest du alle Infos über den Mitarbeiter als PDF unter diesem Link: {{ PDF_LINK }}\n\n{% endif %}Falls du noch irgendwelche anderen Informationen benötigen solltest, kannst du dich bei der it@tub.co melden!\n\nVielen Dank und schöne Grüße,\nDie IT.',
},
'onboarding_key': {
'subject_template': '[Schlüssel] {{ FULL_NAME }} | Anfrage von {{ REQUESTED_BY }}',
'body_template': 'Hallo,\n\nbitte Schlüssel vorbereiten für:\nName: {{ FULL_NAME }}\nAbteilung: {{ DEPARTMENT }}\nVertragsbeginn: {{ CONTRACT_START }}\nAngefordert von: {{ REQUESTED_BY }}\n',
},
'onboarding_reference': {
'subject_template': '[Referenz Onboarding] {{ FULL_NAME }} | Ihre Anfrage',
'body_template': 'Diese E-Mail dient als Referenz für Ihre Onboarding-Anfrage.\nName: {{ FULL_NAME }}\nAbteilung: {{ DEPARTMENT }}\nVertragsbeginn: {{ CONTRACT_START }}\nAngefordert von: {{ REQUESTED_BY }}\n',
},
'offboarding_it': {
'subject_template': '[Offboarding] {{ FULL_NAME }} | Anfrage von {{ REQUESTED_BY }}',
'body_template': 'Neue Offboarding-Anfrage für {{ FULL_NAME }}.\nAbteilung: {{ DEPARTMENT }}\nLetzter Arbeitstag: {{ LAST_WORKING_DAY }}\nAngefordert von: {{ REQUESTED_BY }}\nBitte IT-Offboarding durchführen.',
},
'offboarding_general_info': {
'subject_template': '[Info Offboarding] {{ FULL_NAME }} | Anfrage von {{ REQUESTED_BY }}',
'body_template': 'Neue Offboarding-Anfrage für {{ FULL_NAME }}.\nAbteilung: {{ DEPARTMENT }}\nLetzter Arbeitstag: {{ LAST_WORKING_DAY }}\nAngefordert von: {{ REQUESTED_BY }}\n',
},
'offboarding_hr_works_disable': {
'subject_template': '[HR Works Deaktivierung] {{ FULL_NAME }} | Anfrage von {{ REQUESTED_BY }}',
'body_template': 'Bitte HR Works Zugriff deaktivieren für {{ FULL_NAME }} ({{ EMAIL }}) zum {{ LAST_WORKING_DAY }}.\nAngefordert von: {{ REQUESTED_BY }}\n',
},
'offboarding_reference': {
'subject_template': '[Referenz Offboarding] {{ FULL_NAME }} | Ihre Anfrage',
'body_template': 'Diese E-Mail dient als Referenz für Ihre Offboarding-Anfrage.\nName: {{ FULL_NAME }}\nAbteilung: {{ DEPARTMENT }}\nLetzter Arbeitstag: {{ LAST_WORKING_DAY }}\nAngefordert von: {{ REQUESTED_BY }}\n',
},
}
for key, payload in templates.items():
NotificationTemplate.objects.get_or_create(
key=key,
defaults={
'subject_template': payload['subject_template'],
'body_template': payload['body_template'],
'is_active': True,
},
)
def noop_reverse(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('workflows', '0011_notificationtemplate'),
]
operations = [
migrations.RunPython(seed_notification_templates, noop_reverse),
]

View File

@@ -0,0 +1,33 @@
# Generated by Django 5.1.5 on 2026-03-09 14:55
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0012_seed_notification_templates'),
]
operations = [
migrations.CreateModel(
name='SystemEmailConfig',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(default='Default SMTP', max_length=120, unique=True)),
('is_active', models.BooleanField(default=False)),
('host', models.CharField(blank=True, max_length=255)),
('port', models.PositiveIntegerField(default=587)),
('username', models.CharField(blank=True, max_length=255)),
('password', models.CharField(blank=True, max_length=255)),
('use_tls', models.BooleanField(default=True)),
('use_ssl', models.BooleanField(default=False)),
('from_email', models.EmailField(blank=True, max_length=254)),
('updated_at', models.DateTimeField(auto_now=True)),
],
options={
'verbose_name': 'System SMTP Konfiguration',
'verbose_name_plural': 'System SMTP Konfigurationen',
},
),
]

View File

@@ -0,0 +1,32 @@
# Generated by Django 5.1.5 on 2026-03-09 15:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0013_systememailconfig'),
]
operations = [
migrations.CreateModel(
name='FormFieldConfig',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('form_type', models.CharField(choices=[('onboarding', 'Onboarding'), ('offboarding', 'Offboarding')], max_length=20)),
('field_name', models.CharField(max_length=80)),
('sort_order', models.PositiveIntegerField(default=0)),
('is_visible', models.BooleanField(default=True)),
('is_required', models.BooleanField(blank=True, default=None, null=True)),
('label_override', models.CharField(blank=True, max_length=255)),
('help_text_override', models.TextField(blank=True)),
],
options={
'verbose_name': 'Formularfeld-Konfiguration',
'verbose_name_plural': 'Formularfeld-Konfigurationen',
'ordering': ['form_type', 'sort_order', 'field_name'],
'unique_together': {('form_type', 'field_name')},
},
),
]

View File

@@ -0,0 +1,86 @@
# Generated by Codex on 2026-03-09
from django.db import migrations
ONBOARDING_FIELDS = [
'full_name',
'gender',
'job_title',
'department',
'work_email',
'order_business_cards',
'business_card_name',
'business_card_title',
'business_card_email',
'business_card_phone',
'contract_start',
'employment_type',
'employment_end_date',
'handover_date',
'group_mailboxes_required_choice',
'group_mailboxes',
'needed_devices_multi',
'additional_hardware_needed_choice',
'additional_hardware_multi',
'additional_hardware_other',
'needed_software_multi',
'additional_software_needed_choice',
'additional_software_multi',
'additional_software',
'needed_accesses_multi',
'additional_access_needed_choice',
'additional_access_text',
'needed_workspace_groups_multi',
'needed_resources_multi',
'successor_required_choice',
'successor_name',
'inherit_phone_number_choice',
'phone_number_choice',
'additional_notes',
'signature_url',
'signature_image',
'onboarded_by_email',
'agreement_confirm',
]
OFFBOARDING_FIELDS = [
'full_name',
'work_email',
'department',
'job_title',
'last_working_day',
'notes',
'requested_by_email',
]
def seed_defaults(apps, schema_editor):
FormFieldConfig = apps.get_model('workflows', 'FormFieldConfig')
for idx, name in enumerate(ONBOARDING_FIELDS):
FormFieldConfig.objects.get_or_create(
form_type='onboarding',
field_name=name,
defaults={'sort_order': idx, 'is_visible': True},
)
for idx, name in enumerate(OFFBOARDING_FIELDS):
FormFieldConfig.objects.get_or_create(
form_type='offboarding',
field_name=name,
defaults={'sort_order': idx, 'is_visible': True},
)
def noop_reverse(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('workflows', '0014_formfieldconfig'),
]
operations = [
migrations.RunPython(seed_defaults, noop_reverse),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.5 on 2026-03-09 19:55
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0015_seed_formfieldconfig_defaults'),
]
operations = [
migrations.AddField(
model_name='formfieldconfig',
name='page_key',
field=models.CharField(blank=True, choices=[('', 'Automatisch'), ('stammdaten', 'Stammdaten'), ('vertrag', 'Vertrag'), ('itsetup', 'IT-Setup'), ('abschluss', 'Abschluss')], default='', max_length=20),
),
]

View File

@@ -0,0 +1,69 @@
# Generated by Codex on 2026-03-09
from django.db import migrations
ONBOARDING_DEFAULT_PAGE = {
'full_name': 'stammdaten',
'gender': 'stammdaten',
'job_title': 'stammdaten',
'department': 'stammdaten',
'work_email': 'stammdaten',
'order_business_cards': 'stammdaten',
'business_card_name': 'stammdaten',
'business_card_title': 'stammdaten',
'business_card_email': 'stammdaten',
'business_card_phone': 'stammdaten',
'contract_start': 'vertrag',
'employment_type': 'vertrag',
'employment_end_date': 'vertrag',
'handover_date': 'vertrag',
'group_mailboxes_required_choice': 'vertrag',
'group_mailboxes': 'vertrag',
'needed_devices_multi': 'itsetup',
'additional_hardware_needed_choice': 'itsetup',
'additional_hardware_multi': 'itsetup',
'additional_hardware_other': 'itsetup',
'needed_software_multi': 'itsetup',
'additional_software_needed_choice': 'itsetup',
'additional_software_multi': 'itsetup',
'additional_software': 'itsetup',
'needed_accesses_multi': 'itsetup',
'additional_access_needed_choice': 'itsetup',
'additional_access_text': 'itsetup',
'needed_workspace_groups_multi': 'itsetup',
'needed_resources_multi': 'itsetup',
'successor_required_choice': 'itsetup',
'successor_name': 'itsetup',
'inherit_phone_number_choice': 'itsetup',
'phone_number_choice': 'itsetup',
'additional_notes': 'abschluss',
'signature_url': 'abschluss',
'signature_image': 'abschluss',
'onboarded_by_email': 'abschluss',
'agreement_confirm': 'abschluss',
}
def seed_page_keys(apps, schema_editor):
FormFieldConfig = apps.get_model('workflows', 'FormFieldConfig')
for cfg in FormFieldConfig.objects.filter(form_type='onboarding'):
if cfg.page_key:
continue
cfg.page_key = ONBOARDING_DEFAULT_PAGE.get(cfg.field_name, 'abschluss')
cfg.save(update_fields=['page_key'])
def noop_reverse(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('workflows', '0016_formfieldconfig_page_key'),
]
operations = [
migrations.RunPython(seed_page_keys, noop_reverse),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.5 on 2026-03-10 09:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0017_seed_formfieldconfig_page_keys'),
]
operations = [
migrations.AddField(
model_name='workflowconfig',
name='nextcloud_enabled_override',
field=models.BooleanField(blank=True, default=None, help_text='Leer = ENV-Wert nutzen, Ja = erzwingen aktiv, Nein = erzwingen inaktiv', null=True, verbose_name='Nextcloud Upload aktiviert (Override)'),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.1.5 on 2026-03-10 10:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0018_workflowconfig_nextcloud_enabled_override'),
]
operations = [
migrations.AddField(
model_name='offboardingrequest',
name='requested_by_name',
field=models.CharField(blank=True, max_length=255, verbose_name='Name der anfordernden Person'),
),
migrations.AddField(
model_name='onboardingrequest',
name='onboarded_by_name',
field=models.CharField(blank=True, max_length=255, verbose_name='Name der anfordernden Person'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.5 on 2026-03-10 12:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0019_offboardingrequest_requested_by_name_and_more'),
]
operations = [
migrations.AddField(
model_name='workflowconfig',
name='email_test_mode_override',
field=models.BooleanField(blank=True, default=None, help_text='Leer = ENV-Wert nutzen, Ja = Testmodus erzwingen, Nein = Produktionsmodus erzwingen', null=True, verbose_name='E-Mail Testmodus aktiv (Override)'),
),
]

View File

@@ -0,0 +1,78 @@
# Generated by Django 5.1.5 on 2026-03-10 12:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0020_workflowconfig_email_test_mode_override'),
]
operations = [
migrations.AddField(
model_name='workflowconfig',
name='email_account',
field=models.EmailField(blank=True, max_length=254, verbose_name='E-Mail Konto'),
),
migrations.AddField(
model_name='workflowconfig',
name='email_password',
field=models.CharField(blank=True, max_length=255, verbose_name='E-Mail Passwort'),
),
migrations.AddField(
model_name='workflowconfig',
name='imap_server',
field=models.CharField(blank=True, max_length=255, verbose_name='IMAP Server'),
),
migrations.AddField(
model_name='workflowconfig',
name='mailbox',
field=models.CharField(blank=True, default='INBOX', max_length=120, verbose_name='Mailbox'),
),
migrations.AddField(
model_name='workflowconfig',
name='nextcloud_base_url_override',
field=models.CharField(blank=True, max_length=500, verbose_name='Nextcloud Base URL (Override)'),
),
migrations.AddField(
model_name='workflowconfig',
name='nextcloud_directory_override',
field=models.CharField(blank=True, max_length=255, verbose_name='Nextcloud Verzeichnis (Override)'),
),
migrations.AddField(
model_name='workflowconfig',
name='nextcloud_password_override',
field=models.CharField(blank=True, max_length=255, verbose_name='Nextcloud Passwort (Override)'),
),
migrations.AddField(
model_name='workflowconfig',
name='nextcloud_username_override',
field=models.CharField(blank=True, max_length=255, verbose_name='Nextcloud Benutzername (Override)'),
),
migrations.AddField(
model_name='workflowconfig',
name='smtp_port',
field=models.PositiveIntegerField(default=465, verbose_name='SMTP Port'),
),
migrations.AddField(
model_name='workflowconfig',
name='smtp_server',
field=models.CharField(blank=True, max_length=255, verbose_name='SMTP Server'),
),
migrations.AddField(
model_name='workflowconfig',
name='smtp_use_ssl',
field=models.BooleanField(default=True, verbose_name='SMTP SSL nutzen'),
),
migrations.AddField(
model_name='workflowconfig',
name='smtp_use_tls',
field=models.BooleanField(default=False, verbose_name='SMTP TLS nutzen'),
),
migrations.AddField(
model_name='workflowconfig',
name='sync_interval_seconds',
field=models.PositiveIntegerField(default=60, verbose_name='Sync-Intervall (Sekunden)'),
),
]

View File

@@ -0,0 +1,34 @@
# Generated by Django 5.1.5 on 2026-03-10 12:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0021_workflowconfig_email_account_and_more'),
]
operations = [
migrations.CreateModel(
name='NotificationRule',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=120)),
('is_active', models.BooleanField(default=True)),
('event_type', models.CharField(choices=[('onboarding', 'Onboarding'), ('offboarding', 'Offboarding')], max_length=20)),
('field_name', models.CharField(blank=True, max_length=80)),
('operator', models.CharField(choices=[('always', 'Immer'), ('contains', 'Enthält'), ('equals', 'Ist gleich'), ('is_true', 'Ist aktiv/Ja'), ('is_false', 'Ist inaktiv/Nein')], default='always', max_length=20)),
('expected_value', models.CharField(blank=True, max_length=255)),
('recipients', models.TextField(help_text='Mehrere E-Mail-Adressen mit Komma, Semikolon oder Zeilenumbruch trennen.')),
('template_key', models.CharField(blank=True, max_length=60)),
('custom_subject', models.CharField(blank=True, max_length=255)),
('custom_body', models.TextField(blank=True)),
('include_pdf_attachment', models.BooleanField(default=False)),
('sort_order', models.PositiveIntegerField(default=0)),
],
options={
'ordering': ['event_type', 'sort_order', 'id'],
},
),
]

View File

@@ -0,0 +1,37 @@
# Generated by Django 5.1.5 on 2026-03-10 12:56
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0022_notificationrule'),
]
operations = [
migrations.AlterField(
model_name='notificationtemplate',
name='key',
field=models.CharField(choices=[('onboarding_it', 'Onboarding: IT'), ('onboarding_general_info', 'Onboarding: Allgemeine Info'), ('onboarding_business_card', 'Onboarding: Visitenkarte'), ('onboarding_hr_works', 'Onboarding: HR Works'), ('onboarding_key', 'Onboarding: Schlüssel'), ('onboarding_reference', 'Onboarding: Referenz Anfordernde Person'), ('onboarding_welcome', 'Onboarding: Welcome E-Mail'), ('offboarding_it', 'Offboarding: IT'), ('offboarding_general_info', 'Offboarding: Allgemeine Info'), ('offboarding_hr_works_disable', 'Offboarding: HR Works Deaktivierung'), ('offboarding_reference', 'Offboarding: Referenz Anfordernde Person')], max_length=60, unique=True),
),
migrations.CreateModel(
name='ScheduledWelcomeEmail',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('recipient_email', models.EmailField(max_length=254)),
('send_at', models.DateTimeField()),
('status', models.CharField(choices=[('scheduled', 'Geplant'), ('sent', 'Gesendet'), ('failed', 'Fehlgeschlagen')], default='scheduled', max_length=20)),
('celery_task_id', models.CharField(blank=True, max_length=100)),
('sent_at', models.DateTimeField(blank=True, null=True)),
('last_error', models.TextField(blank=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('onboarding_request', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='workflows.onboardingrequest')),
],
options={
'ordering': ['-send_at', '-id'],
},
),
]

View File

@@ -0,0 +1,33 @@
# Generated by Django 5.1.5 on 2026-03-10 13:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('workflows', '0023_alter_notificationtemplate_key_scheduledwelcomeemail'),
]
operations = [
migrations.AddField(
model_name='workflowconfig',
name='welcome_email_delay_days',
field=models.PositiveIntegerField(default=5, verbose_name='Welcome E-Mail Verzögerung (Tage)'),
),
migrations.AddField(
model_name='workflowconfig',
name='welcome_include_pdf',
field=models.BooleanField(default=True, verbose_name='Welcome E-Mail mit PDF-Anhang'),
),
migrations.AddField(
model_name='workflowconfig',
name='welcome_sender_email',
field=models.EmailField(blank=True, max_length=254, verbose_name='Welcome E-Mail Absender'),
),
migrations.AlterField(
model_name='scheduledwelcomeemail',
name='status',
field=models.CharField(choices=[('scheduled', 'Geplant'), ('paused', 'Pausiert'), ('cancelled', 'Abgebrochen'), ('sent', 'Gesendet'), ('failed', 'Fehlgeschlagen')], default='scheduled', max_length=20),
),
]

View File