Initialize clean CSR inventory repository
This commit is contained in:
233
inventory/migrations/0001_initial.py
Normal file
233
inventory/migrations/0001_initial.py
Normal file
@@ -0,0 +1,233 @@
|
||||
# Generated by Django 5.2.17 on 2026-09-19 12:26
|
||||
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Employee',
|
||||
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)),
|
||||
('code', models.CharField(max_length=12, unique=True)),
|
||||
('name', models.CharField(max_length=160)),
|
||||
('active', models.BooleanField(db_index=True, default=True)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['code'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FieldDefinition',
|
||||
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)),
|
||||
('name', models.CharField(max_length=120)),
|
||||
('key', models.SlugField(max_length=80, unique=True)),
|
||||
('field_type', models.CharField(choices=[('text', 'Text'), ('long_text', 'Langer Text'), ('integer', 'Ganzzahl'), ('decimal', 'Dezimalzahl'), ('boolean', 'Ja/Nein'), ('date', 'Datum'), ('select', 'Auswahl'), ('multi_select', 'Mehrfachauswahl')], max_length=20)),
|
||||
('unit', models.CharField(blank=True, max_length=30)),
|
||||
('required', models.BooleanField(default=False)),
|
||||
('active', models.BooleanField(db_index=True, default=True)),
|
||||
('show_in_list', models.BooleanField(default=False)),
|
||||
('filterable', models.BooleanField(default=False)),
|
||||
('searchable', models.BooleanField(default=False)),
|
||||
('sort_order', models.PositiveIntegerField(default=0)),
|
||||
('group', models.CharField(default='Zusatzfelder', max_length=80)),
|
||||
('allow_custom_values', models.BooleanField(default=False)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['sort_order', 'name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='NumberSequence',
|
||||
fields=[
|
||||
('name', models.CharField(max_length=30, primary_key=True, serialize=False)),
|
||||
('last_value', models.PositiveIntegerField(default=0)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ChoiceValue',
|
||||
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)),
|
||||
('kind', models.CharField(choices=[('status', 'Status'), ('recipient', 'Empfänger'), ('location', 'Ort'), ('device_type', 'Typ'), ('ram', 'RAM-Vorschlag'), ('ssd', 'SSD-Vorschlag'), ('hdd', 'HDD-Vorschlag'), ('display', 'Displaygröße')], db_index=True, max_length=30)),
|
||||
('label', models.CharField(max_length=120)),
|
||||
('numeric_value', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
|
||||
('active', models.BooleanField(db_index=True, default=True)),
|
||||
('sort_order', models.PositiveIntegerField(default=0)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['kind', 'sort_order', 'label'],
|
||||
'indexes': [models.Index(fields=['kind', 'active', 'sort_order'], name='inventory_c_kind_320c2f_idx')],
|
||||
'constraints': [models.UniqueConstraint(fields=('kind', 'label'), name='unique_choice_label_per_kind')],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Device',
|
||||
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)),
|
||||
('number', models.PositiveIntegerField(db_index=True, editable=False, unique=True)),
|
||||
('shelf', models.CharField(blank=True, db_index=True, max_length=80)),
|
||||
('date', models.DateField(db_index=True, default=django.utils.timezone.localdate)),
|
||||
('ticket', models.CharField(blank=True, db_index=True, max_length=120)),
|
||||
('price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
|
||||
('battery', models.CharField(choices=[('YES', 'JA'), ('NO', 'NEIN'), ('UNKNOWN', 'UNBEKANNT')], default='UNKNOWN', max_length=10)),
|
||||
('wifi', models.CharField(choices=[('YES', 'JA'), ('NO', 'NEIN'), ('UNKNOWN', 'UNBEKANNT')], default='UNKNOWN', max_length=10)),
|
||||
('lan', models.CharField(choices=[('YES', 'JA'), ('NO', 'NEIN'), ('UNKNOWN', 'UNBEKANNT')], default='UNKNOWN', max_length=10)),
|
||||
('display_inches', models.DecimalField(blank=True, decimal_places=1, max_digits=4, null=True)),
|
||||
('ram_gb', models.PositiveIntegerField(blank=True, db_index=True, null=True)),
|
||||
('ssd_gb', models.PositiveIntegerField(blank=True, db_index=True, null=True)),
|
||||
('hdd_gb', models.PositiveIntegerField(blank=True, db_index=True, null=True)),
|
||||
('cpu', models.CharField(blank=True, db_index=True, max_length=200)),
|
||||
('model', models.CharField(blank=True, db_index=True, max_length=200)),
|
||||
('donor', models.CharField(blank=True, max_length=200)),
|
||||
('comment', models.TextField(blank=True)),
|
||||
('custom_values', models.JSONField(blank=True, default=dict)),
|
||||
('archived_at', models.DateTimeField(blank=True, db_index=True, null=True)),
|
||||
('archived_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='archived_devices', to=settings.AUTH_USER_MODEL)),
|
||||
('device_type', models.ForeignKey(blank=True, limit_choices_to={'kind': 'device_type'}, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='type_devices', to='inventory.choicevalue')),
|
||||
('location', models.ForeignKey(blank=True, limit_choices_to={'kind': 'location'}, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='location_devices', to='inventory.choicevalue')),
|
||||
('recipient', models.ForeignKey(blank=True, limit_choices_to={'kind': 'recipient'}, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='recipient_devices', to='inventory.choicevalue')),
|
||||
('status', models.ForeignKey(limit_choices_to={'kind': 'status'}, on_delete=django.db.models.deletion.PROTECT, related_name='status_devices', to='inventory.choicevalue')),
|
||||
('employee', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='inventory.employee')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-number'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FieldOption',
|
||||
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)),
|
||||
('label', models.CharField(max_length=120)),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('sort_order', models.PositiveIntegerField(default=0)),
|
||||
('field', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='options', to='inventory.fielddefinition')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['sort_order', 'label'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ImportJob',
|
||||
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)),
|
||||
('file', models.FileField(upload_to='imports/%Y/%m/')),
|
||||
('original_name', models.CharField(max_length=255)),
|
||||
('status', models.CharField(choices=[('UPLOADED', 'Hochgeladen'), ('COMPLETED', 'Abgeschlossen'), ('FAILED', 'Fehlgeschlagen')], default='UPLOADED', max_length=12)),
|
||||
('headers', models.JSONField(default=list)),
|
||||
('preview_rows', models.JSONField(default=list)),
|
||||
('result', models.JSONField(default=dict)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='import_jobs', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SavedView',
|
||||
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)),
|
||||
('name', models.CharField(max_length=120)),
|
||||
('filters', models.JSONField(default=dict)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='saved_views', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserPreference',
|
||||
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)),
|
||||
('visible_columns', models.JSONField(blank=True, default=list)),
|
||||
('column_order', models.JSONField(blank=True, default=list)),
|
||||
('column_widths', models.JSONField(blank=True, default=dict)),
|
||||
('page_size', models.PositiveSmallIntegerField(default=50)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='inventory_preferences', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserProfile',
|
||||
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)),
|
||||
('role', models.CharField(choices=[('ADMIN', 'Administrator'), ('EDITOR', 'Bearbeiter'), ('VIEWER', 'Betrachter')], default='VIEWER', max_length=10)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AuditLog',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('action', models.CharField(choices=[('CREATE', 'Erstellt'), ('UPDATE', 'Geändert'), ('ARCHIVE', 'Archiviert'), ('RESTORE', 'Wiederhergestellt'), ('IMPORT', 'Importiert')], max_length=10)),
|
||||
('field', models.CharField(blank=True, max_length=100)),
|
||||
('old_value', models.TextField(blank=True)),
|
||||
('new_value', models.TextField(blank=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, db_index=True)),
|
||||
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='audit_entries', to=settings.AUTH_USER_MODEL)),
|
||||
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='audit_entries', to='inventory.device')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created_at', '-id'],
|
||||
'indexes': [models.Index(fields=['device', '-created_at'], name='inventory_a_device__78ae29_idx')],
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='device',
|
||||
index=models.Index(fields=['archived_at', '-number'], name='inventory_d_archive_2483fe_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='device',
|
||||
index=models.Index(fields=['status', 'archived_at'], name='inventory_d_status__f41a2e_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='device',
|
||||
index=models.Index(fields=['device_type', 'archived_at'], name='inventory_d_device__ec71d5_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='device',
|
||||
index=models.Index(fields=['employee', 'archived_at'], name='inventory_d_employe_e23a79_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='device',
|
||||
index=models.Index(fields=['recipient', 'archived_at'], name='inventory_d_recipie_5290ea_idx'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='fieldoption',
|
||||
constraint=models.UniqueConstraint(fields=('field', 'label'), name='unique_custom_field_option'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='savedview',
|
||||
constraint=models.UniqueConstraint(fields=('user', 'name'), name='unique_saved_view_name'),
|
||||
),
|
||||
]
|
||||
30
inventory/migrations/0002_postgres_search_indexes.py
Normal file
30
inventory/migrations/0002_postgres_search_indexes.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def add_postgres_indexes(apps, schema_editor):
|
||||
if schema_editor.connection.vendor != "postgresql":
|
||||
return
|
||||
statements = [
|
||||
"CREATE EXTENSION IF NOT EXISTS pg_trgm",
|
||||
"CREATE INDEX IF NOT EXISTS inventory_device_cpu_trgm ON inventory_device USING gin (cpu gin_trgm_ops)",
|
||||
"CREATE INDEX IF NOT EXISTS inventory_device_model_trgm ON inventory_device USING gin (model gin_trgm_ops)",
|
||||
"CREATE INDEX IF NOT EXISTS inventory_device_ticket_trgm ON inventory_device USING gin (ticket gin_trgm_ops)",
|
||||
"CREATE INDEX IF NOT EXISTS inventory_device_donor_trgm ON inventory_device USING gin (donor gin_trgm_ops)",
|
||||
"CREATE INDEX IF NOT EXISTS inventory_device_custom_values_gin ON inventory_device USING gin (custom_values jsonb_path_ops)",
|
||||
]
|
||||
with schema_editor.connection.cursor() as cursor:
|
||||
for statement in statements:
|
||||
cursor.execute(statement)
|
||||
|
||||
|
||||
def remove_postgres_indexes(apps, schema_editor):
|
||||
if schema_editor.connection.vendor != "postgresql":
|
||||
return
|
||||
with schema_editor.connection.cursor() as cursor:
|
||||
for name in ["inventory_device_cpu_trgm", "inventory_device_model_trgm", "inventory_device_ticket_trgm", "inventory_device_donor_trgm", "inventory_device_custom_values_gin"]:
|
||||
cursor.execute(f"DROP INDEX IF EXISTS {name}")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("inventory", "0001_initial")]
|
||||
operations = [migrations.RunPython(add_postgres_indexes, remove_postgres_indexes)]
|
||||
51
inventory/migrations/0003_audit_revert_and_device_types.py
Normal file
51
inventory/migrations/0003_audit_revert_and_device_types.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def add_device_types(apps, schema_editor):
|
||||
ChoiceValue = apps.get_model("inventory", "ChoiceValue")
|
||||
for order, label in enumerate(("Bildschirm", "Drucker"), start=3):
|
||||
ChoiceValue.objects.update_or_create(
|
||||
kind="device_type", label=label,
|
||||
defaults={"active": True, "sort_order": order},
|
||||
)
|
||||
|
||||
|
||||
def remove_device_types(apps, schema_editor):
|
||||
ChoiceValue = apps.get_model("inventory", "ChoiceValue")
|
||||
ChoiceValue.objects.filter(kind="device_type", label__in=("Bildschirm", "Drucker")).delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("inventory", "0002_postgres_search_indexes"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="auditlog", name="field_key",
|
||||
field=models.CharField(blank=True, max_length=120),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="auditlog", name="old_data",
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="auditlog", name="new_data",
|
||||
field=models.JSONField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="auditlog", name="reverted_at",
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="auditlog", name="reverted_by",
|
||||
field=models.ForeignKey(
|
||||
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="reverted_audit_entries", to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
migrations.RunPython(add_device_types, remove_device_types),
|
||||
]
|
||||
24
inventory/migrations/0004_choicevalue_color.py
Normal file
24
inventory/migrations/0004_choicevalue_color.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
STATUS_COLORS = {
|
||||
"Eingang": "#2563eb", "Entsorgt": "#64748b", "Fertig": "#15803d",
|
||||
"Defekt": "#dc2626", "Reserviert": "#b45309", "Ausgegeben": "#7c3aed", "Intern": "#0891b2",
|
||||
}
|
||||
|
||||
|
||||
def set_status_colors(apps, schema_editor):
|
||||
ChoiceValue = apps.get_model("inventory", "ChoiceValue")
|
||||
for label, color in STATUS_COLORS.items():
|
||||
ChoiceValue.objects.filter(kind="status", label=label).update(color=color)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("inventory", "0003_audit_revert_and_device_types")]
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="choicevalue", name="color",
|
||||
field=models.CharField(blank=True, max_length=20),
|
||||
),
|
||||
migrations.RunPython(set_status_colors, migrations.RunPython.noop),
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
# Generated by Django 5.2.17 on 2026-09-21 13:01
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0004_choicevalue_color'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='auditlog',
|
||||
name='api_client',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='hwid',
|
||||
field=models.CharField(blank=True, db_index=True, max_length=255),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='InventoryAPIKey',
|
||||
fields=[
|
||||
('id', models.CharField(editable=False, max_length=150, primary_key=True, serialize=False, unique=True)),
|
||||
('prefix', models.CharField(editable=False, max_length=8, unique=True)),
|
||||
('hashed_key', models.CharField(editable=False, max_length=150)),
|
||||
('created', models.DateTimeField(auto_now_add=True, db_index=True)),
|
||||
('name', models.CharField(default=None, help_text='A free-form name for the API key. Need not be unique. 50 characters max.', max_length=50)),
|
||||
('revoked', models.BooleanField(blank=True, default=False, help_text='If the API key is revoked, clients cannot use it anymore. (This cannot be undone.)')),
|
||||
('expiry_date', models.DateTimeField(blank=True, help_text='Once API key expires, clients cannot use it anymore.', null=True, verbose_name='Expires')),
|
||||
('can_read', models.BooleanField(default=True)),
|
||||
('can_write', models.BooleanField(default=False)),
|
||||
('last_used_at', models.DateTimeField(blank=True, editable=False, null=True)),
|
||||
('last_used_ip', models.GenericIPAddressField(blank=True, editable=False, null=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_inventory_api_keys', to=settings.AUTH_USER_MODEL)),
|
||||
('service_user', models.ForeignKey(help_text='Technisches oder persönliches Konto, dem API-Änderungen zugerechnet werden.', on_delete=django.db.models.deletion.PROTECT, related_name='inventory_api_keys', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'API-Schlüssel',
|
||||
'verbose_name_plural': 'API-Schlüssel',
|
||||
'ordering': ('-created',),
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
16
inventory/migrations/0006_device_revision.py
Normal file
16
inventory/migrations/0006_device_revision.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("inventory", "0005_auditlog_api_client_device_hwid_inventoryapikey")]
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="device", name="revision",
|
||||
field=models.PositiveBigIntegerField(default=1, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="device", name="updated_at",
|
||||
field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
|
||||
),
|
||||
]
|
||||
67
inventory/migrations/0007_workflow_tasks.py
Normal file
67
inventory/migrations/0007_workflow_tasks.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def initial_stages(apps, schema_editor):
|
||||
Device = apps.get_model("inventory", "Device")
|
||||
for device in Device.objects.select_related("status").iterator():
|
||||
label = device.status.label.casefold()
|
||||
if label == "ausgegeben":
|
||||
stage = "ISSUED"
|
||||
elif label in {"fertig", "reserviert"}:
|
||||
stage = "STORAGE"
|
||||
elif label == "defekt":
|
||||
stage = "REPAIR"
|
||||
else:
|
||||
stage = "INTAKE"
|
||||
Device.objects.filter(pk=device.pk).update(stage=stage)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("inventory", "0006_device_revision"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="device", name="stage",
|
||||
field=models.CharField(max_length=12, choices=[
|
||||
("INTAKE", "Eingang"), ("INSPECTION", "Inspektion"),
|
||||
("REPAIR", "Reparatur"), ("STORAGE", "Lagerung"), ("ISSUED", "Ausgegeben"),
|
||||
], default="INTAKE", db_index=True),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="DeviceTask",
|
||||
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=200)),
|
||||
("description", models.TextField(blank=True)),
|
||||
("state", models.CharField(max_length=8, choices=[("OPEN", "Offen"), ("DONE", "Erledigt")], default="OPEN", db_index=True)),
|
||||
("completed_at", models.DateTimeField(null=True, blank=True)),
|
||||
("due_date", models.DateField(null=True, blank=True)),
|
||||
("assigned_to", models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.SET_NULL, related_name="assigned_device_tasks", null=True, blank=True)),
|
||||
("completed_by", models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.SET_NULL, related_name="completed_device_tasks", null=True, blank=True)),
|
||||
("created_by", models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.SET_NULL, related_name="created_device_tasks", null=True)),
|
||||
("device", models.ForeignKey(to="inventory.device", on_delete=django.db.models.deletion.CASCADE, related_name="tasks")),
|
||||
],
|
||||
options={"ordering": ["state", "-created_at"]},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="WorkflowEvent",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("from_stage", models.CharField(max_length=12, choices=[("INTAKE", "Eingang"), ("INSPECTION", "Inspektion"), ("REPAIR", "Reparatur"), ("STORAGE", "Lagerung"), ("ISSUED", "Ausgegeben")], blank=True)),
|
||||
("to_stage", models.CharField(max_length=12, choices=[("INTAKE", "Eingang"), ("INSPECTION", "Inspektion"), ("REPAIR", "Reparatur"), ("STORAGE", "Lagerung"), ("ISSUED", "Ausgegeben")])),
|
||||
("note", models.CharField(max_length=500, blank=True)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("device", models.ForeignKey(to="inventory.device", on_delete=django.db.models.deletion.CASCADE, related_name="workflow_events")),
|
||||
("user", models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.SET_NULL, null=True)),
|
||||
],
|
||||
options={"ordering": ["-created_at", "-id"]},
|
||||
),
|
||||
migrations.RunPython(initial_stages, migrations.RunPython.noop),
|
||||
]
|
||||
36
inventory/migrations/0008_normalize_hardware_by_type.py
Normal file
36
inventory/migrations/0008_normalize_hardware_by_type.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
COMPUTER = {"cpu", "hwid", "ram_gb", "ssd_gb", "hdd_gb", "display_inches", "battery", "wifi", "lan"}
|
||||
ALLOWED = {
|
||||
"laptop": COMPUTER,
|
||||
"aio": COMPUTER - {"battery"},
|
||||
"desktop": COMPUTER - {"battery", "display_inches"},
|
||||
"bildschirm": {"display_inches"},
|
||||
"drucker": {"wifi", "lan"},
|
||||
}
|
||||
|
||||
|
||||
def normalize(apps, schema_editor):
|
||||
Device = apps.get_model("inventory", "Device")
|
||||
for device in Device.objects.select_related("device_type").iterator():
|
||||
if device.device_type is None:
|
||||
continue
|
||||
fields = COMPUTER - ALLOWED.get(device.device_type.label.strip().casefold(), COMPUTER)
|
||||
if not fields:
|
||||
continue
|
||||
changes = {}
|
||||
legacy = dict((device.custom_values or {}).get("legacy_hardware") or {})
|
||||
for field in fields:
|
||||
value = getattr(device, field)
|
||||
if value not in (None, "", "UNKNOWN"):
|
||||
legacy[field] = str(value)
|
||||
changes[field] = None if Device._meta.get_field(field).null else "UNKNOWN" if field in {"battery", "wifi", "lan"} else ""
|
||||
if legacy:
|
||||
changes["custom_values"] = {**(device.custom_values or {}), "legacy_hardware": legacy}
|
||||
Device.objects.filter(pk=device.pk).update(**changes)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("inventory", "0007_workflow_tasks")]
|
||||
operations = [migrations.RunPython(normalize, migrations.RunPython.noop)]
|
||||
237
inventory/migrations/0009_split_device_specifications.py
Normal file
237
inventory/migrations/0009_split_device_specifications.py
Normal file
@@ -0,0 +1,237 @@
|
||||
# Generated by Django 5.2.17 on 2026-09-26 10:54
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def copy_to_specifications(apps, schema_editor):
|
||||
Device = apps.get_model("inventory", "Device")
|
||||
Computer = apps.get_model("inventory", "ComputerSpecification")
|
||||
Monitor = apps.get_model("inventory", "MonitorSpecification")
|
||||
Printer = apps.get_model("inventory", "PrinterSpecification")
|
||||
for device in Device.objects.select_related("device_type").iterator(chunk_size=500):
|
||||
label = device.device_type.label.strip().casefold() if device.device_type else ""
|
||||
if label == "drucker":
|
||||
Printer.objects.create(device_id=device.pk, wifi=device.wifi, lan=device.lan)
|
||||
elif label == "bildschirm":
|
||||
Monitor.objects.create(device_id=device.pk, display_inches=device.display_inches)
|
||||
else:
|
||||
Computer.objects.create(
|
||||
device_id=device.pk, cpu=device.cpu, hwid=device.hwid,
|
||||
ram_gb=device.ram_gb, ssd_gb=device.ssd_gb, hdd_gb=device.hdd_gb,
|
||||
display_inches=device.display_inches, battery=device.battery,
|
||||
wifi=device.wifi, lan=device.lan,
|
||||
)
|
||||
|
||||
|
||||
def copy_back_to_devices(apps, schema_editor):
|
||||
Device = apps.get_model("inventory", "Device")
|
||||
Computer = apps.get_model("inventory", "ComputerSpecification")
|
||||
Monitor = apps.get_model("inventory", "MonitorSpecification")
|
||||
Printer = apps.get_model("inventory", "PrinterSpecification")
|
||||
for device in Device.objects.select_related("device_type").iterator(chunk_size=500):
|
||||
label = device.device_type.label.strip().casefold() if device.device_type else ""
|
||||
if label == "drucker":
|
||||
spec = Printer.objects.filter(device_id=device.pk).first()
|
||||
elif label == "bildschirm":
|
||||
spec = Monitor.objects.filter(device_id=device.pk).first()
|
||||
else:
|
||||
spec = Computer.objects.filter(device_id=device.pk).first()
|
||||
if spec:
|
||||
Device.objects.filter(pk=device.pk).update(**{
|
||||
name: getattr(spec, name) for name in (
|
||||
"cpu", "hwid", "ram_gb", "ssd_gb", "hdd_gb", "display_inches", "battery", "wifi", "lan",
|
||||
) if hasattr(spec, name)
|
||||
})
|
||||
|
||||
|
||||
def computer_search_index(apps, schema_editor):
|
||||
if schema_editor.connection.vendor == "postgresql":
|
||||
schema_editor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS inventory_computer_cpu_trgm "
|
||||
"ON inventory_computerspecification USING gin (cpu gin_trgm_ops)"
|
||||
)
|
||||
|
||||
|
||||
def drop_computer_search_index(apps, schema_editor):
|
||||
if schema_editor.connection.vendor == "postgresql":
|
||||
schema_editor.execute("DROP INDEX IF EXISTS inventory_computer_cpu_trgm")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("inventory", "0008_normalize_hardware_by_type"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="ComputerSpecification",
|
||||
fields=[
|
||||
(
|
||||
"device",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
related_name="computer_specification",
|
||||
serialize=False,
|
||||
to="inventory.device",
|
||||
),
|
||||
),
|
||||
("cpu", models.CharField(blank=True, db_index=True, max_length=200)),
|
||||
("hwid", models.CharField(blank=True, db_index=True, max_length=255)),
|
||||
(
|
||||
"ram_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"ssd_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"hdd_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"display_inches",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=1, max_digits=4, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"battery",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"wifi",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"lan",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="MonitorSpecification",
|
||||
fields=[
|
||||
(
|
||||
"device",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
related_name="monitor_specification",
|
||||
serialize=False,
|
||||
to="inventory.device",
|
||||
),
|
||||
),
|
||||
(
|
||||
"display_inches",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=1, max_digits=4, null=True
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="PrinterSpecification",
|
||||
fields=[
|
||||
(
|
||||
"device",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
related_name="printer_specification",
|
||||
serialize=False,
|
||||
to="inventory.device",
|
||||
),
|
||||
),
|
||||
(
|
||||
"wifi",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"lan",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.RunPython(copy_to_specifications, copy_back_to_devices),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="battery",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="cpu",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="display_inches",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="hdd_gb",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="hwid",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="lan",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="ram_gb",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="ssd_gb",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="device",
|
||||
name="wifi",
|
||||
),
|
||||
migrations.RunPython(computer_search_index, drop_computer_search_index),
|
||||
]
|
||||
63
inventory/migrations/0010_workflow_integrity.py
Normal file
63
inventory/migrations/0010_workflow_integrity.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# Generated by Django 5.2.17 on 2026-09-26 11:04
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("inventory", "0009_split_device_specifications"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name="devicetask",
|
||||
index=models.Index(
|
||||
fields=["state", "due_date"], name="inventory_d_state_bfd57d_idx"
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="devicetask",
|
||||
index=models.Index(
|
||||
fields=["device", "state"], name="inventory_d_device__f5a9da_idx"
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="workflowevent",
|
||||
index=models.Index(
|
||||
fields=["device", "-created_at"], name="inventory_w_device__f6b3a5_idx"
|
||||
),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="device",
|
||||
constraint=models.CheckConstraint(
|
||||
condition=models.Q(
|
||||
(
|
||||
"stage__in",
|
||||
["INTAKE", "INSPECTION", "REPAIR", "STORAGE", "ISSUED"],
|
||||
)
|
||||
),
|
||||
name="valid_device_stage",
|
||||
),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="devicetask",
|
||||
constraint=models.CheckConstraint(
|
||||
condition=models.Q(("state__in", ["OPEN", "DONE"])),
|
||||
name="valid_device_task_state",
|
||||
),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="devicetask",
|
||||
constraint=models.CheckConstraint(
|
||||
condition=models.Q(
|
||||
models.Q(("completed_at__isnull", True), ("state", "OPEN")),
|
||||
models.Q(("completed_at__isnull", False), ("state", "DONE")),
|
||||
_connector="OR",
|
||||
),
|
||||
name="device_task_completion_matches_state",
|
||||
),
|
||||
),
|
||||
]
|
||||
98
inventory/migrations/0011_inspectionrecord_repairrecord.py
Normal file
98
inventory/migrations/0011_inspectionrecord_repairrecord.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# Generated by Django 5.2.17 on 2026-09-26 12:11
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("inventory", "0010_workflow_integrity"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="InspectionRecord",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("defects", models.TextField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"device",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="inspections",
|
||||
to="inventory.device",
|
||||
),
|
||||
),
|
||||
(
|
||||
"recorded_by",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["-created_at", "-id"],
|
||||
"indexes": [
|
||||
models.Index(
|
||||
fields=["device", "-created_at"],
|
||||
name="inventory_i_device__4a3af8_idx",
|
||||
)
|
||||
],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RepairRecord",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("work_done", models.TextField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"device",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="repairs",
|
||||
to="inventory.device",
|
||||
),
|
||||
),
|
||||
(
|
||||
"recorded_by",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["-created_at", "-id"],
|
||||
"indexes": [
|
||||
models.Index(
|
||||
fields=["device", "-created_at"],
|
||||
name="inventory_r_device__58bce5_idx",
|
||||
)
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,302 @@
|
||||
# Generated by Django 5.2.17 on 2026-09-28 19:27
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
TYPE_TABLES = {
|
||||
"laptop": "LaptopSpecification",
|
||||
"desktop": "DesktopSpecification",
|
||||
"aio": "AllInOneSpecification",
|
||||
"all-in-one": "AllInOneSpecification",
|
||||
"all in one": "AllInOneSpecification",
|
||||
}
|
||||
|
||||
|
||||
def move_computer_rows(apps, schema_editor):
|
||||
Computer = apps.get_model("inventory", "ComputerSpecification")
|
||||
targets = {name: apps.get_model("inventory", name) for name in set(TYPE_TABLES.values())}
|
||||
for source in Computer.objects.select_related("device__device_type").iterator(chunk_size=500):
|
||||
label = source.device.device_type.label.strip().casefold() if source.device.device_type else ""
|
||||
target_name = TYPE_TABLES.get(label)
|
||||
if not target_name:
|
||||
continue
|
||||
target = targets[target_name]
|
||||
fields = [field.name for field in target._meta.fields if field.name != "device"]
|
||||
target.objects.create(device_id=source.device_id, **{name: getattr(source, name) for name in fields})
|
||||
source.delete()
|
||||
|
||||
|
||||
def restore_computer_rows(apps, schema_editor):
|
||||
Computer = apps.get_model("inventory", "ComputerSpecification")
|
||||
for name in set(TYPE_TABLES.values()):
|
||||
target = apps.get_model("inventory", name)
|
||||
for source in target.objects.iterator(chunk_size=500):
|
||||
fields = [field.name for field in Computer._meta.fields if field.name != "device"]
|
||||
Computer.objects.create(device_id=source.device_id, **{
|
||||
field: getattr(source, field) for field in fields if hasattr(source, field)
|
||||
})
|
||||
|
||||
|
||||
def create_cpu_indexes(apps, schema_editor):
|
||||
if schema_editor.connection.vendor == "postgresql":
|
||||
for table, name in (("inventory_laptopspecification", "inventory_laptop_cpu_trgm"),
|
||||
("inventory_desktopspecification", "inventory_desktop_cpu_trgm"),
|
||||
("inventory_allinonespecification", "inventory_aio_cpu_trgm")):
|
||||
schema_editor.execute(f"CREATE INDEX {name} ON {table} USING gin (cpu gin_trgm_ops)")
|
||||
|
||||
|
||||
def drop_cpu_indexes(apps, schema_editor):
|
||||
if schema_editor.connection.vendor == "postgresql":
|
||||
for name in ("inventory_laptop_cpu_trgm", "inventory_desktop_cpu_trgm", "inventory_aio_cpu_trgm"):
|
||||
schema_editor.execute(f"DROP INDEX IF EXISTS {name}")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("inventory", "0011_inspectionrecord_repairrecord"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="AllInOneSpecification",
|
||||
fields=[
|
||||
("cpu", models.CharField(blank=True, db_index=True, max_length=200)),
|
||||
("hwid", models.CharField(blank=True, db_index=True, max_length=255)),
|
||||
(
|
||||
"ram_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"ssd_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"hdd_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"wifi",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"lan",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
("ports", models.CharField(blank=True, max_length=255)),
|
||||
(
|
||||
"device",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
related_name="aio_specification",
|
||||
serialize=False,
|
||||
to="inventory.device",
|
||||
),
|
||||
),
|
||||
(
|
||||
"display_inches",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=1, max_digits=4, null=True
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="DesktopSpecification",
|
||||
fields=[
|
||||
("cpu", models.CharField(blank=True, db_index=True, max_length=200)),
|
||||
("hwid", models.CharField(blank=True, db_index=True, max_length=255)),
|
||||
(
|
||||
"ram_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"ssd_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"hdd_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"wifi",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"lan",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
("ports", models.CharField(blank=True, max_length=255)),
|
||||
(
|
||||
"device",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
related_name="desktop_specification",
|
||||
serialize=False,
|
||||
to="inventory.device",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="LaptopSpecification",
|
||||
fields=[
|
||||
("cpu", models.CharField(blank=True, db_index=True, max_length=200)),
|
||||
("hwid", models.CharField(blank=True, db_index=True, max_length=255)),
|
||||
(
|
||||
"ram_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"ssd_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"hdd_gb",
|
||||
models.PositiveIntegerField(blank=True, db_index=True, null=True),
|
||||
),
|
||||
(
|
||||
"wifi",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
(
|
||||
"lan",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
("ports", models.CharField(blank=True, max_length=255)),
|
||||
(
|
||||
"device",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
related_name="laptop_specification",
|
||||
serialize=False,
|
||||
to="inventory.device",
|
||||
),
|
||||
),
|
||||
(
|
||||
"display_inches",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=1, max_digits=4, null=True
|
||||
),
|
||||
),
|
||||
(
|
||||
"battery",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("YES", "JA"),
|
||||
("NO", "NEIN"),
|
||||
("UNKNOWN", "UNBEKANNT"),
|
||||
],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="computerspecification",
|
||||
name="ports",
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="monitorspecification",
|
||||
name="ports",
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="monitorspecification",
|
||||
name="resolution",
|
||||
field=models.CharField(blank=True, max_length=80),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="printerspecification",
|
||||
name="color_printing",
|
||||
field=models.CharField(
|
||||
choices=[("YES", "JA"), ("NO", "NEIN"), ("UNKNOWN", "UNBEKANNT")],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="printerspecification",
|
||||
name="duplex",
|
||||
field=models.CharField(
|
||||
choices=[("YES", "JA"), ("NO", "NEIN"), ("UNKNOWN", "UNBEKANNT")],
|
||||
default="UNKNOWN",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="printerspecification",
|
||||
name="ports",
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="printerspecification",
|
||||
name="print_technology",
|
||||
field=models.CharField(blank=True, max_length=80),
|
||||
),
|
||||
migrations.RunPython(move_computer_rows, restore_computer_rows),
|
||||
migrations.RunPython(create_cpu_indexes, drop_cpu_indexes),
|
||||
]
|
||||
0
inventory/migrations/__init__.py
Normal file
0
inventory/migrations/__init__.py
Normal file
Reference in New Issue
Block a user