From 85e4e59b3a477d147899ab0d32a9f089ca53cc57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <git@imaniti.org>
Date: Thu, 16 Feb 2023 12:38:53 +0900
Subject: [PATCH] finish admin interface, for the time being

---
 contracts/admin.py                            |  39 +-
 contracts/migrations/0001_initial.py          | 724 ++++++++++++++----
 ...contract_all_parties_sign_date_and_more.py |  29 -
 ...003_alter_contract_public_status_set_by.py |  21 -
 contracts/models.py                           | 154 ++--
 model-desc.md                                 |   9 +-
 6 files changed, 706 insertions(+), 270 deletions(-)
 delete mode 100644 contracts/migrations/0002_alter_contract_all_parties_sign_date_and_more.py
 delete mode 100644 contracts/migrations/0003_alter_contract_public_status_set_by.py

diff --git a/contracts/admin.py b/contracts/admin.py
index 64cc7eb..5241206 100644
--- a/contracts/admin.py
+++ b/contracts/admin.py
@@ -27,6 +27,16 @@ class IndexHiddenModelAdmin(MarkdownxGuardedModelAdmin):
 # BEGIN Contracts
 
 
+class ContracteeSignatureInline(admin.TabularInline):
+    model = ContracteeSignature
+    extra = 0
+
+
+class SigneeSignatureInline(admin.TabularInline):
+    model = SigneeSignature
+    extra = 0
+
+
 class ContractFileInline(admin.TabularInline):
     model = ContractFile
     extra = 0
@@ -37,19 +47,13 @@ class ContractIntentInline(admin.TabularInline):
     extra = 0
 
 
-class ContractIssueInline(admin.TabularInline):
-    model = Contract.issues.through
-    extra = 0
-
-
 class ContractAdmin(MarkdownxGuardedModelAdmin):
     form = ContractAdminForm
 
     fields = (
+        "created_by",
         "type",
         "subtype",
-        "signee_signatures",
-        "contractee_signatures",
         "valid_start_date",
         "valid_end_date",
         "legal_state",
@@ -58,6 +62,7 @@ class ContractAdmin(MarkdownxGuardedModelAdmin):
         "publishing_rejection_comment",
         "tender_url",
         "identifier",
+        "issues",
         "notes",
         "summary",
         "primary_contract",
@@ -69,12 +74,21 @@ class ContractAdmin(MarkdownxGuardedModelAdmin):
         "filing_area",
     )
 
+    readonly_fields = ("created_by",)
+
     inlines = (
+        ContracteeSignatureInline,
+        SigneeSignatureInline,
         ContractFileInline,
         ContractIntentInline,
-        ContractIssueInline,
     )
 
+    def save_model(self, request, obj, form, change) -> None:
+        if obj.created_by is None:
+            obj.created_by = request.user
+
+        super().save_model(request, obj, form, change)
+
 
 # END Contracts
 
@@ -91,6 +105,7 @@ class SigneeAdmin(MarkdownxGuardedModelAdmin):
 
     inlines = (
         SigneeRepresentativeInline,
+        SigneeSignatureInline,
     )
 
 
@@ -100,15 +115,15 @@ class ContracteeRepresentativeInline(admin.TabularInline):
 
 
 class ContracteeAdmin(MarkdownxGuardedModelAdmin):
-    inlines = (
-        ContracteeRepresentativeInline,
-    )
+    inlines = (ContracteeRepresentativeInline, ContracteeSignatureInline)
 
 
 # END Signing parties
 
 
 for model in (
+    SigneeSignature,
+    ContracteeSignature,
     SigneeRepresentative,
     ContracteeRepresentative,
     ContractSubtype,
@@ -117,8 +132,6 @@ for model in (
     admin.site.register(model, IndexHiddenModelAdmin)
 
 for model in (
-    SigneeSignature,
-    ContracteeSignature,
     ContractIssue,
     ContractFilingArea,
 ):
diff --git a/contracts/migrations/0001_initial.py b/contracts/migrations/0001_initial.py
index 466d34d..00dd0b8 100644
--- a/contracts/migrations/0001_initial.py
+++ b/contracts/migrations/0001_initial.py
@@ -1,15 +1,15 @@
-# Generated by Django 4.1.4 on 2023-02-15 17:12
+# Generated by Django 4.1.4 on 2023-02-16 03:36
 
-from django.conf import settings
-from django.db import migrations, models
 import django.db.models.deletion
 import django_countries.fields
 import markdownx.models
+from django.conf import settings
+from django.db import migrations, models
+
 import shared.models
 
 
 class Migration(migrations.Migration):
-
     initial = True
 
     dependencies = [
@@ -18,225 +18,669 @@ class Migration(migrations.Migration):
 
     operations = [
         migrations.CreateModel(
-            name='Contract',
+            name="Contract",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('type', models.CharField(choices=[('primary', 'Hlavní'), ('amendment', 'Dodatek'), ('framework_order', 'Objednávka u rámcové smlouvy')], default='primary', max_length=15, verbose_name='Typ')),
-                ('contains_nda', models.BooleanField(default=False, verbose_name='Obsahuje NDA')),
-                ('all_parties_sign_date', models.DateField(verbose_name='Datum podpisu všech stran')),
-                ('valid_start_date', models.DateField(verbose_name='Začátek účinnosti')),
-                ('valid_end_date', models.DateField(verbose_name='Konec platnosti')),
-                ('legal_state', models.CharField(choices=[('valid', 'Platná'), ('effective', 'Účinná'), ('not_effective', 'Neúčinná'), ('invalid', 'Neplatná')], max_length=13, verbose_name='Stav právního ujednání')),
-                ('public_state', models.CharField(choices=[('unknown', 'Nová'), ('yes', 'Zveřejněná'), ('no', 'Neveřejná')], max_length=7, verbose_name='Veřejnost smlouvy')),
-                ('paper_form_state', models.CharField(choices=[('sent', 'Odeslaná'), ('stored', 'Uložená'), ('to_shred', 'Ke skartaci'), ('shredded', 'Skartovaná')], max_length=8, verbose_name='Stav papírové formy')),
-                ('publishing_rejection_comment', models.CharField(blank=True, help_text='Obsah není veřejně přístupný.', max_length=65536, null=True, verbose_name='Důvod nezveřejnění')),
-                ('tender_url', models.URLField(blank=True, max_length=256, null=True, verbose_name='Odkaz na výběrové řízení')),
-                ('identifier', models.CharField(max_length=128, verbose_name='Identifikační číslo')),
-                ('notes', markdownx.models.MarkdownxField(blank=True, help_text='Poznámky jsou viditelné pro všechny, kteří mohou smlouvu spravovat.', null=True, verbose_name='Obsah')),
-                ('summary', models.CharField(blank=True, help_text='Obsah není veřejně přístupný.', max_length=65536, null=True, verbose_name='Rekapitulace')),
-                ('expected_cost_total', models.IntegerField(verbose_name='Očekáváná celková cena')),
-                ('expected_cost_year', models.IntegerField(verbose_name='Očekáváná cena za rok')),
-                ('expected_cost_month', models.IntegerField(verbose_name='Očekáváná cena za měsíc')),
-                ('expected_cost_hour', models.IntegerField(verbose_name='Očekáváná cena za hodinu')),
-                ('agreement_url', models.URLField(blank=True, max_length=256, null=True, verbose_name='Odkaz na schválení')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "type",
+                    models.CharField(
+                        choices=[
+                            ("primary", "Hlavní"),
+                            ("amendment", "Dodatek"),
+                            ("framework_order", "Objednávka u rámcové smlouvy"),
+                        ],
+                        default="primary",
+                        max_length=15,
+                        verbose_name="Typ",
+                    ),
+                ),
+                (
+                    "contains_nda",
+                    models.BooleanField(default=False, verbose_name="Obsahuje NDA"),
+                ),
+                (
+                    "all_parties_sign_date",
+                    models.DateField(
+                        blank=True, null=True, verbose_name="Datum podpisu všech stran"
+                    ),
+                ),
+                (
+                    "valid_start_date",
+                    models.DateField(verbose_name="Začátek účinnosti"),
+                ),
+                ("valid_end_date", models.DateField(verbose_name="Konec platnosti")),
+                (
+                    "legal_state",
+                    models.CharField(
+                        choices=[
+                            ("valid", "Platná"),
+                            ("effective", "Účinná"),
+                            ("not_effective", "Neúčinná"),
+                            ("invalid", "Neplatná"),
+                        ],
+                        max_length=13,
+                        verbose_name="Stav právního ujednání",
+                    ),
+                ),
+                (
+                    "public_state",
+                    models.CharField(
+                        choices=[("yes", "Veřejná"), ("no", "Neveřejná")],
+                        max_length=7,
+                        verbose_name="Veřejnost smlouvy",
+                    ),
+                ),
+                (
+                    "paper_form_state",
+                    models.CharField(
+                        choices=[
+                            ("sent", "Odeslaná"),
+                            ("stored", "Uložená"),
+                            ("to_shred", "Ke skartaci"),
+                            ("shredded", "Skartovaná"),
+                        ],
+                        max_length=8,
+                        verbose_name="Stav papírové formy",
+                    ),
+                ),
+                (
+                    "publishing_rejection_comment",
+                    models.CharField(
+                        blank=True,
+                        help_text="Obsah není veřejně přístupný.",
+                        max_length=65536,
+                        null=True,
+                        verbose_name="Důvod nezveřejnění",
+                    ),
+                ),
+                (
+                    "tender_url",
+                    models.URLField(
+                        blank=True,
+                        max_length=256,
+                        null=True,
+                        verbose_name="Odkaz na výběrové řízení",
+                    ),
+                ),
+                (
+                    "identifier",
+                    models.CharField(
+                        max_length=128, verbose_name="Identifikační číslo"
+                    ),
+                ),
+                (
+                    "notes",
+                    markdownx.models.MarkdownxField(
+                        blank=True,
+                        help_text="Poznámky jsou viditelné pro všechny, kteří mohou smlouvu spravovat.",
+                        null=True,
+                        verbose_name="Poznámky",
+                    ),
+                ),
+                (
+                    "summary",
+                    markdownx.models.MarkdownxField(
+                        blank=True,
+                        help_text="Obsah není veřejně přístupný.",
+                        null=True,
+                        verbose_name="Rekapitulace",
+                    ),
+                ),
+                (
+                    "expected_cost_total",
+                    models.IntegerField(
+                        blank=True, null=True, verbose_name="Očekáváná celková cena"
+                    ),
+                ),
+                (
+                    "expected_cost_year",
+                    models.IntegerField(
+                        blank=True, null=True, verbose_name="Očekáváná cena za rok"
+                    ),
+                ),
+                (
+                    "expected_cost_month",
+                    models.IntegerField(
+                        blank=True, null=True, verbose_name="Očekáváná cena za měsíc"
+                    ),
+                ),
+                (
+                    "expected_cost_hour",
+                    models.IntegerField(
+                        blank=True, null=True, verbose_name="Očekáváná cena za hodinu"
+                    ),
+                ),
+                (
+                    "agreement_url",
+                    models.URLField(
+                        blank=True,
+                        max_length=256,
+                        null=True,
+                        verbose_name="Odkaz na schválení",
+                    ),
+                ),
+                (
+                    "created_by",
+                    models.ForeignKey(
+                        blank=True,
+                        help_text="Informace není veřejně přístupná. Pokud vytváříš novou smlouvu, budeš to ty.",
+                        null=True,
+                        on_delete=django.db.models.deletion.SET_NULL,
+                        related_name="uploaded_contracts",
+                        to=settings.AUTH_USER_MODEL,
+                        verbose_name="Vytvořena uživatelem",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Smlouva',
-                'verbose_name_plural': 'Smlouvy',
+                "verbose_name": "Smlouva",
+                "verbose_name_plural": "Smlouvy",
             },
         ),
         migrations.CreateModel(
-            name='Contractee',
+            name="Contractee",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(default='Česká pirátská strana', max_length=256, verbose_name='Jméno')),
-                ('address_street_with_number', models.CharField(default='Na Moráni 360/3', max_length=256, verbose_name='Ulice, č.p.')),
-                ('address_district', models.CharField(default='Praha 2', max_length=256, verbose_name='Obec')),
-                ('address_zip', models.CharField(default='128 00', max_length=16, verbose_name='PSČ')),
-                ('address_country', django_countries.fields.CountryField(default='CZ', max_length=2, verbose_name='Země')),
-                ('ico_number', models.CharField(blank=True, default='71339698', max_length=16, null=True, verbose_name='IČO')),
-                ('department', models.CharField(blank=True, max_length=128, null=True, verbose_name='Organizační složka')),
-                ('color', models.CharField(blank=True, max_length=6, null=True, verbose_name='Barva')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "name",
+                    models.CharField(
+                        default="Česká pirátská strana",
+                        max_length=256,
+                        verbose_name="Jméno",
+                    ),
+                ),
+                (
+                    "address_street_with_number",
+                    models.CharField(
+                        default="Na Moráni 360/3",
+                        max_length=256,
+                        verbose_name="Ulice, č.p.",
+                    ),
+                ),
+                (
+                    "address_district",
+                    models.CharField(
+                        default="Praha 2", max_length=256, verbose_name="Obec"
+                    ),
+                ),
+                (
+                    "address_zip",
+                    models.CharField(
+                        default="128 00", max_length=16, verbose_name="PSČ"
+                    ),
+                ),
+                (
+                    "address_country",
+                    django_countries.fields.CountryField(
+                        default="CZ", max_length=2, verbose_name="Země"
+                    ),
+                ),
+                (
+                    "ico_number",
+                    models.CharField(
+                        blank=True,
+                        default="71339698",
+                        max_length=16,
+                        null=True,
+                        verbose_name="IČO",
+                    ),
+                ),
+                (
+                    "department",
+                    models.CharField(
+                        blank=True,
+                        max_length=128,
+                        null=True,
+                        verbose_name="Organizační složka",
+                    ),
+                ),
+                (
+                    "color",
+                    models.CharField(
+                        blank=True, max_length=6, null=True, verbose_name="Barva"
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Naše smluvní strana',
-                'verbose_name_plural': 'Naše smluvní strany',
+                "verbose_name": "Naše smluvní strana",
+                "verbose_name_plural": "Naše smluvní strany",
             },
         ),
         migrations.CreateModel(
-            name='ContractFilingArea',
+            name="ContractFilingArea",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=32, verbose_name='Jméno')),
-                ('person_responsible', models.CharField(max_length=256, verbose_name='Odpovědná osoba')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(max_length=32, verbose_name="Jméno")),
+                (
+                    "person_responsible",
+                    models.CharField(max_length=256, verbose_name="Odpovědná osoba"),
+                ),
             ],
             options={
-                'verbose_name': 'Spisovna',
-                'verbose_name_plural': 'Spisovny',
+                "verbose_name": "Spisovna",
+                "verbose_name_plural": "Spisovny",
             },
             bases=(shared.models.NameStrMixin, models.Model),
         ),
         migrations.CreateModel(
-            name='ContractIssue',
+            name="ContractIssue",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=32, verbose_name='Jméno')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(max_length=32, verbose_name="Jméno")),
             ],
             options={
-                'verbose_name': 'Problém se smlouvou',
-                'verbose_name_plural': 'Problémy se smlouvami',
+                "verbose_name": "Problém se smlouvou",
+                "verbose_name_plural": "Problémy se smlouvami",
             },
             bases=(shared.models.NameStrMixin, models.Model),
         ),
         migrations.CreateModel(
-            name='ContractSubtype',
+            name="ContractSubtype",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=32, verbose_name='Jméno')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(max_length=32, verbose_name="Jméno")),
             ],
             options={
-                'verbose_name': 'Podtyp smlouvy',
-                'verbose_name_plural': 'Podtypy smlouvy',
+                "verbose_name": "Podtyp smlouvy",
+                "verbose_name_plural": "Podtypy smlouvy",
             },
             bases=(shared.models.NameStrMixin, models.Model),
         ),
         migrations.CreateModel(
-            name='Signee',
+            name="Signee",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=256, verbose_name='Jméno')),
-                ('is_legal_entity', models.BooleanField(help_text='Důležité označit správně! Pokud není osoba právnická, zveřejňujeme pouze obec a zemi.', verbose_name='Je právnická osoba')),
-                ('address_street_with_number', models.CharField(help_text='Viditelné pouze u právnických osob.', max_length=256, verbose_name='Ulice, č.p.')),
-                ('address_district', models.CharField(max_length=256, verbose_name='Obec')),
-                ('address_zip', models.CharField(help_text='Viditelné pouze u právnických osob.', max_length=16, verbose_name='PSČ')),
-                ('address_country', django_countries.fields.CountryField(max_length=2, verbose_name='Země')),
-                ('ico_number', models.CharField(blank=True, max_length=16, null=True, verbose_name='IČO')),
-                ('date_of_birth', models.DateField(blank=True, null=True, verbose_name='Datum narození')),
-                ('department', models.CharField(blank=True, max_length=128, null=True, verbose_name='Organizační složka')),
-                ('color', models.CharField(blank=True, max_length=6, null=True, verbose_name='Barva')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(max_length=256, verbose_name="Jméno")),
+                (
+                    "is_legal_entity",
+                    models.BooleanField(
+                        help_text="Důležité označit správně! Pokud není osoba právnická, zveřejňujeme pouze obec a zemi.",
+                        verbose_name="Je právnická osoba",
+                    ),
+                ),
+                (
+                    "address_street_with_number",
+                    models.CharField(
+                        help_text="Viditelné pouze u právnických osob.",
+                        max_length=256,
+                        verbose_name="Ulice, č.p.",
+                    ),
+                ),
+                (
+                    "address_district",
+                    models.CharField(max_length=256, verbose_name="Obec"),
+                ),
+                (
+                    "address_zip",
+                    models.CharField(
+                        help_text="Viditelné pouze u právnických osob.",
+                        max_length=16,
+                        verbose_name="PSČ",
+                    ),
+                ),
+                (
+                    "address_country",
+                    django_countries.fields.CountryField(
+                        max_length=2, verbose_name="Země"
+                    ),
+                ),
+                (
+                    "ico_number",
+                    models.CharField(
+                        blank=True, max_length=16, null=True, verbose_name="IČO"
+                    ),
+                ),
+                (
+                    "date_of_birth",
+                    models.DateField(
+                        blank=True, null=True, verbose_name="Datum narození"
+                    ),
+                ),
+                (
+                    "department",
+                    models.CharField(
+                        blank=True,
+                        max_length=128,
+                        null=True,
+                        verbose_name="Organizační složka",
+                    ),
+                ),
+                (
+                    "color",
+                    models.CharField(
+                        blank=True, max_length=6, null=True, verbose_name="Barva"
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Jiná smluvní strana',
-                'verbose_name_plural': 'Ostatní smluvní strany',
+                "verbose_name": "Jiná smluvní strana",
+                "verbose_name_plural": "Ostatní smluvní strany",
             },
         ),
         migrations.CreateModel(
-            name='SigneeSignature',
+            name="SigneeSignature",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('date', models.DateField(verbose_name='Datum podpisu')),
-                ('signee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='signatures', to='contracts.signee', verbose_name='Smluvní strana')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("date", models.DateField(verbose_name="Datum podpisu")),
+                (
+                    "contract",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="signee_signatures",
+                        to="contracts.contract",
+                        verbose_name="Podpisy jiných smluvních stran",
+                    ),
+                ),
+                (
+                    "signee",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="signatures",
+                        to="contracts.signee",
+                        verbose_name="Smluvní strana",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Podpis jiné smluvní strany',
-                'verbose_name_plural': 'Podpisy ostatních smluvních stran',
+                "verbose_name": "Podpis jiné smluvní strany",
+                "verbose_name_plural": "Podpisy ostatních smluvních stran",
             },
         ),
         migrations.CreateModel(
-            name='SigneeRepresentative',
+            name="SigneeRepresentative",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=256, verbose_name='Jméno')),
-                ('function', models.CharField(blank=True, max_length=256, null=True, verbose_name='Funkce')),
-                ('role', models.CharField(blank=True, max_length=256, null=True, verbose_name='Role')),
-                ('signee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='representatives', to='contracts.signee', verbose_name='Smluvní strana')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(max_length=256, verbose_name="Jméno")),
+                (
+                    "function",
+                    models.CharField(
+                        blank=True, max_length=256, null=True, verbose_name="Funkce"
+                    ),
+                ),
+                (
+                    "role",
+                    models.CharField(
+                        blank=True, max_length=256, null=True, verbose_name="Role"
+                    ),
+                ),
+                (
+                    "signee",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="representatives",
+                        to="contracts.signee",
+                        verbose_name="Smluvní strana",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Zástupce',
-                'verbose_name_plural': 'Zástupci',
+                "verbose_name": "Zástupce",
+                "verbose_name_plural": "Zástupci",
             },
         ),
         migrations.CreateModel(
-            name='ContractIntent',
+            name="ContractIntent",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('url', models.URLField(blank=True, max_length=256, null=True, verbose_name='Odkaz')),
-                ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='intents', to='contracts.contract', verbose_name='Smlouva')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "url",
+                    models.URLField(
+                        blank=True, max_length=256, null=True, verbose_name="Odkaz"
+                    ),
+                ),
+                (
+                    "contract",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="intents",
+                        to="contracts.contract",
+                        verbose_name="Smlouva",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Záměr',
-                'verbose_name_plural': 'Záměry',
+                "verbose_name": "Záměr",
+                "verbose_name_plural": "Záměry",
             },
         ),
         migrations.CreateModel(
-            name='ContractFile',
+            name="ContractFile",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(blank=True, max_length=128, null=True, verbose_name='Jméno')),
-                ('is_public', models.BooleanField(default=False, verbose_name='Veřejně dostupný')),
-                ('file', models.FileField(upload_to='', verbose_name='Soubor')),
-                ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='contracts.contract', verbose_name='Soubory')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "name",
+                    models.CharField(
+                        blank=True, max_length=128, null=True, verbose_name="Jméno"
+                    ),
+                ),
+                (
+                    "is_public",
+                    models.BooleanField(default=False, verbose_name="Veřejně dostupný"),
+                ),
+                ("file", models.FileField(upload_to="", verbose_name="Soubor")),
+                (
+                    "contract",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="files",
+                        to="contracts.contract",
+                        verbose_name="Soubory",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Soubor',
-                'verbose_name_plural': 'Soubory',
+                "verbose_name": "Soubor",
+                "verbose_name_plural": "Soubory",
             },
             bases=(shared.models.NameStrMixin, models.Model),
         ),
         migrations.CreateModel(
-            name='ContracteeSignature',
+            name="ContracteeSignature",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('date', models.DateField(verbose_name='Datum podpisu')),
-                ('contractee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='signatures', to='contracts.contractee', verbose_name='Smluvní strana')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("date", models.DateField(verbose_name="Datum podpisu")),
+                (
+                    "contract",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="contractee_signatures",
+                        to="contracts.contract",
+                        verbose_name="Podpisy našich smluvních stran",
+                    ),
+                ),
+                (
+                    "contractee",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="signatures",
+                        to="contracts.contractee",
+                        verbose_name="Smluvní strana",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Podpis naší smluvní strany',
-                'verbose_name_plural': 'Podpisy našich smluvních stran',
+                "verbose_name": "Podpis naší smluvní strany",
+                "verbose_name_plural": "Podpisy našich smluvních stran",
             },
         ),
         migrations.CreateModel(
-            name='ContracteeRepresentative',
+            name="ContracteeRepresentative",
             fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=256, verbose_name='Jméno')),
-                ('function', models.CharField(blank=True, max_length=256, null=True, verbose_name='Funkce')),
-                ('role', models.CharField(blank=True, max_length=256, null=True, verbose_name='Role')),
-                ('contractee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='representatives', to='contracts.contractee', verbose_name='Smluvní strana')),
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(max_length=256, verbose_name="Jméno")),
+                (
+                    "function",
+                    models.CharField(
+                        blank=True, max_length=256, null=True, verbose_name="Funkce"
+                    ),
+                ),
+                (
+                    "role",
+                    models.CharField(
+                        blank=True, max_length=256, null=True, verbose_name="Role"
+                    ),
+                ),
+                (
+                    "contractee",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="representatives",
+                        to="contracts.contractee",
+                        verbose_name="Smluvní strana",
+                    ),
+                ),
             ],
             options={
-                'verbose_name': 'Zástupce',
-                'verbose_name_plural': 'Zástupci',
+                "verbose_name": "Zástupce",
+                "verbose_name_plural": "Zástupci",
             },
         ),
         migrations.AddField(
-            model_name='contract',
-            name='contractee_signatures',
-            field=models.ManyToManyField(to='contracts.contracteesignature', verbose_name='Podpisy našich smluvních stran'),
-        ),
-        migrations.AddField(
-            model_name='contract',
-            name='filing_area',
-            field=models.ForeignKey(blank=True, help_text='Obsah není veřejně přístupný.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='filed_contracts', to='contracts.contractfilingarea', verbose_name='Spisovna'),
-        ),
-        migrations.AddField(
-            model_name='contract',
-            name='issues',
-            field=models.ManyToManyField(to='contracts.contractissue', verbose_name='Problémy'),
-        ),
-        migrations.AddField(
-            model_name='contract',
-            name='primary_contract',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='subcontracts', to='contracts.contract', verbose_name='Hlavní smlouva'),
+            model_name="contract",
+            name="filing_area",
+            field=models.ForeignKey(
+                blank=True,
+                help_text="Obsah není veřejně přístupný.",
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="filed_contracts",
+                to="contracts.contractfilingarea",
+                verbose_name="Spisovna",
+            ),
         ),
         migrations.AddField(
-            model_name='contract',
-            name='public_status_set_by',
-            field=models.ForeignKey(help_text='Obsah není veřejně přístupný.', on_delete=django.db.models.deletion.CASCADE, related_name='public_status_altered_contracts', to=settings.AUTH_USER_MODEL, verbose_name='Zveřejněno / nezveřejněno uživatelem'),
+            model_name="contract",
+            name="issues",
+            field=models.ManyToManyField(
+                blank=True, to="contracts.contractissue", verbose_name="Problémy"
+            ),
         ),
         migrations.AddField(
-            model_name='contract',
-            name='signee_signatures',
-            field=models.ManyToManyField(to='contracts.signeesignature', verbose_name='Podpisy ostatních smluvních stran'),
+            model_name="contract",
+            name="primary_contract",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="subcontracts",
+                to="contracts.contract",
+                verbose_name="Hlavní smlouva",
+            ),
         ),
         migrations.AddField(
-            model_name='contract',
-            name='subtype',
-            field=models.ManyToManyField(to='contracts.contractsubtype', verbose_name='Podtypy'),
+            model_name="contract",
+            name="public_status_set_by",
+            field=models.ForeignKey(
+                blank=True,
+                help_text="Obsah není veřejně přístupný.",
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="public_status_altered_contracts",
+                to=settings.AUTH_USER_MODEL,
+                verbose_name="Zveřejněno / nezveřejněno uživatelem",
+            ),
         ),
         migrations.AddField(
-            model_name='contract',
-            name='uploaded_by',
-            field=models.ForeignKey(help_text='Informace není veřejně přístupná.', on_delete=django.db.models.deletion.CASCADE, related_name='uploaded_contracts', to=settings.AUTH_USER_MODEL, verbose_name='Nahráno uživatelem'),
+            model_name="contract",
+            name="subtype",
+            field=models.ManyToManyField(
+                blank=True, to="contracts.contractsubtype", verbose_name="Podtypy"
+            ),
         ),
     ]
diff --git a/contracts/migrations/0002_alter_contract_all_parties_sign_date_and_more.py b/contracts/migrations/0002_alter_contract_all_parties_sign_date_and_more.py
deleted file mode 100644
index 463b58e..0000000
--- a/contracts/migrations/0002_alter_contract_all_parties_sign_date_and_more.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Generated by Django 4.1.4 on 2023-02-15 17:19
-
-from django.db import migrations, models
-import markdownx.models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('contracts', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='contract',
-            name='all_parties_sign_date',
-            field=models.DateField(blank=True, null=True, verbose_name='Datum podpisu všech stran'),
-        ),
-        migrations.AlterField(
-            model_name='contract',
-            name='notes',
-            field=markdownx.models.MarkdownxField(blank=True, help_text='Poznámky jsou viditelné pro všechny, kteří mohou smlouvu spravovat.', null=True, verbose_name='Poznámky'),
-        ),
-        migrations.AlterField(
-            model_name='contract',
-            name='summary',
-            field=markdownx.models.MarkdownxField(blank=True, help_text='Obsah není veřejně přístupný.', null=True, verbose_name='Rekapitulace'),
-        ),
-    ]
diff --git a/contracts/migrations/0003_alter_contract_public_status_set_by.py b/contracts/migrations/0003_alter_contract_public_status_set_by.py
deleted file mode 100644
index b662563..0000000
--- a/contracts/migrations/0003_alter_contract_public_status_set_by.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Generated by Django 4.1.4 on 2023-02-15 17:21
-
-from django.conf import settings
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
-        ('contracts', '0002_alter_contract_all_parties_sign_date_and_more'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='contract',
-            name='public_status_set_by',
-            field=models.ForeignKey(blank=True, help_text='Obsah není veřejně přístupný.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='public_status_altered_contracts', to=settings.AUTH_USER_MODEL, verbose_name='Zveřejněno / nezveřejněno uživatelem'),
-        ),
-    ]
diff --git a/contracts/models.py b/contracts/models.py
index 49ab18d..81fb3f6 100644
--- a/contracts/models.py
+++ b/contracts/models.py
@@ -3,8 +3,8 @@ from django.db import models
 from django_countries.fields import CountryField
 from markdownx.models import MarkdownxField
 
-from users.models import User
 from shared.models import NameStrMixin
+from users.models import User
 
 
 class Signee(models.Model):
@@ -128,26 +128,6 @@ class SigneeRepresentative(models.Model):
         return result
 
 
-class SigneeSignature(models.Model):
-    signee = models.ForeignKey(
-        Signee,
-        on_delete=models.CASCADE,
-        related_name="signatures",
-        verbose_name="Smluvní strana",
-    )
-
-    date = models.DateField(
-        verbose_name="Datum podpisu",
-    )
-
-    class Meta:
-        verbose_name = "Podpis jiné smluvní strany"
-        verbose_name_plural = "Podpisy ostatních smluvních stran"
-
-    def __str__(self) -> str:
-        return f"{self.signee.name}, {self.date}"
-
-
 class Contractee(models.Model):
     name = models.CharField(
         max_length=256,
@@ -258,26 +238,6 @@ class ContracteeRepresentative(models.Model):
         return result
 
 
-class ContracteeSignature(models.Model):
-    contractee = models.ForeignKey(
-        Contractee,
-        on_delete=models.CASCADE,
-        related_name="signatures",
-        verbose_name="Smluvní strana",
-    )
-
-    date = models.DateField(
-        verbose_name="Datum podpisu",
-    )
-
-    class Meta:
-        verbose_name = "Podpis naší smluvní strany"
-        verbose_name_plural = "Podpisy našich smluvních stran"
-
-    def __str__(self) -> str:
-        return f"{self.contractee.name}, {self.date}"
-
-
 class ContractSubtype(NameStrMixin, models.Model):
     name = models.CharField(
         max_length=32,
@@ -332,6 +292,7 @@ class Contract(models.Model):
     subtype = models.ManyToManyField(
         ContractSubtype,
         verbose_name="Podtypy",
+        blank=True,
     )
 
     contains_nda = models.BooleanField(
@@ -339,16 +300,6 @@ class Contract(models.Model):
         verbose_name="Obsahuje NDA",
     )
 
-    signee_signatures = models.ManyToManyField(
-        SigneeSignature,
-        verbose_name="Podpisy ostatních smluvních stran",
-    )
-
-    contractee_signatures = models.ManyToManyField(
-        ContracteeSignature,
-        verbose_name="Podpisy našich smluvních stran",
-    )
-
     all_parties_sign_date = models.DateField(
         verbose_name="Datum podpisu všech stran",
         blank=True,
@@ -362,12 +313,14 @@ class Contract(models.Model):
         verbose_name="Konec platnosti",
     )
 
-    uploaded_by = models.ForeignKey(
-        User,
-        on_delete=models.CASCADE,
+    created_by = models.ForeignKey(
+        settings.AUTH_USER_MODEL,
+        blank=True,
+        null=True,
+        on_delete=models.SET_NULL,
         related_name="uploaded_contracts",
-        verbose_name="Nahráno uživatelem",
-        help_text="Informace není veřejně přístupná.",
+        verbose_name="Vytvořena uživatelem",
+        help_text="Informace není veřejně přístupná. Pokud vytváříš novou smlouvu, budeš to ty.",
     )  # WARNING: exclude in admin
 
     class LegalStates(models.TextChoices):
@@ -377,8 +330,7 @@ class Contract(models.Model):
         INVALID = "invalid", "Neplatná"
 
     class PublicStates(models.TextChoices):
-        UNKNOWN = "unknown", "Nová"
-        YES = "yes", "Zveřejněná"
+        YES = "yes", "Veřejná"
         NO = "no", "Neveřejná"
 
     class PaperFormStates(models.TextChoices):
@@ -407,7 +359,7 @@ class Contract(models.Model):
 
     public_status_set_by = models.ForeignKey(
         User,
-        on_delete=models.CASCADE,
+        on_delete=models.SET_NULL,
         blank=True,
         null=True,
         related_name="public_status_altered_contracts",
@@ -438,7 +390,9 @@ class Contract(models.Model):
     issues = models.ManyToManyField(
         ContractIssue,
         verbose_name="Problémy",
+        blank=True,
     )
+
     notes = MarkdownxField(
         blank=True,
         null=True,
@@ -455,20 +409,36 @@ class Contract(models.Model):
 
     primary_contract = models.ForeignKey(
         "Contract",
-        on_delete=models.CASCADE,
+        on_delete=models.SET_NULL,  # TODO: Figure out if we want this behavior
         blank=True,
         null=True,
         related_name="subcontracts",
         verbose_name="Hlavní smlouva",
     )  # WARNING: Dependent on the type!
 
-    expected_cost_total = models.IntegerField(verbose_name="Očekáváná celková cena")
+    expected_cost_total = models.IntegerField(
+        blank=True,
+        null=True,
+        verbose_name="Očekáváná celková cena",
+    )
 
-    expected_cost_year = models.IntegerField(verbose_name="Očekáváná cena za rok")
+    expected_cost_year = models.IntegerField(
+        blank=True,
+        null=True,
+        verbose_name="Očekáváná cena za rok",
+    )
 
-    expected_cost_month = models.IntegerField(verbose_name="Očekáváná cena za měsíc")
+    expected_cost_month = models.IntegerField(
+        blank=True,
+        null=True,
+        verbose_name="Očekáváná cena za měsíc",
+    )
 
-    expected_cost_hour = models.IntegerField(verbose_name="Očekáváná cena za hodinu")
+    expected_cost_hour = models.IntegerField(
+        blank=True,
+        null=True,
+        verbose_name="Očekáváná cena za hodinu",
+    )
 
     agreement_url = models.URLField(
         max_length=256,
@@ -479,7 +449,7 @@ class Contract(models.Model):
 
     filing_area = models.ForeignKey(
         ContractFilingArea,
-        on_delete=models.CASCADE,
+        on_delete=models.SET_NULL,
         blank=True,
         null=True,
         related_name="filed_contracts",
@@ -524,6 +494,60 @@ class ContractFile(NameStrMixin, models.Model):
         verbose_name_plural = "Soubory"
 
 
+class ContracteeSignature(models.Model):
+    contractee = models.ForeignKey(
+        Contractee,
+        on_delete=models.CASCADE,
+        related_name="signatures",
+        verbose_name="Smluvní strana",
+    )
+
+    contract = models.ForeignKey(
+        Contract,
+        on_delete=models.CASCADE,
+        related_name="contractee_signatures",
+        verbose_name="Podpisy našich smluvních stran",
+    )
+
+    date = models.DateField(
+        verbose_name="Datum podpisu",
+    )
+
+    class Meta:
+        verbose_name = "Podpis naší smluvní strany"
+        verbose_name_plural = "Podpisy našich smluvních stran"
+
+    def __str__(self) -> str:
+        return f"{self.contractee.name}, {self.date}"
+
+
+class SigneeSignature(models.Model):
+    signee = models.ForeignKey(
+        Signee,
+        on_delete=models.CASCADE,
+        related_name="signatures",
+        verbose_name="Smluvní strana",
+    )
+
+    contract = models.ForeignKey(
+        Contract,
+        on_delete=models.CASCADE,
+        related_name="signee_signatures",
+        verbose_name="Podpisy jiných smluvních stran",
+    )
+
+    date = models.DateField(
+        verbose_name="Datum podpisu",
+    )
+
+    class Meta:
+        verbose_name = "Podpis jiné smluvní strany"
+        verbose_name_plural = "Podpisy ostatních smluvních stran"
+
+    def __str__(self) -> str:
+        return f"{self.signee.name}, {self.date}"
+
+
 class ContractIntent(models.Model):
     url = models.URLField(
         max_length=256,
diff --git a/model-desc.md b/model-desc.md
index 8a67d61..b17b5b5 100644
--- a/model-desc.md
+++ b/model-desc.md
@@ -15,6 +15,7 @@
 - `Zástupce naší smluvní strany` (propojený s `Naší smluvní stranou`):
     - Celé jméno
     - Funkce
+    - Role
    
 - `Podpis naší smluvní strany` (propojený se `Smlouvou`):
     - Datum
@@ -38,6 +39,7 @@
 - `Zástupce druhé smluvní strany` (propojený s `Druhou smluvní stranou`):
     - Celé jméno
     - Funkce
+    - Role
    
 - `Podpis druhé smluvní strany` (propojený se `Smlouvou`):
     - Datum
@@ -54,6 +56,10 @@
 - `Problém` (propojený se `Smlouvou`):
     - Jméno
 
+- `Soubor` (propojený se `Smlouvou`):
+    - Jméno
+    - Obsah souboru (např. PDF)
+   
 - `Spisovna` (existuje nezávisle):
     - Jméno
     - Jméno odpovědné osoby
@@ -93,8 +99,7 @@
         - `Problémy`
         - Poznámky - sdílený textový blok
         - Sumarizace
-        - PDF originální smlouvy
-        - PDF anonymizované smlouvy
+        - `Soubory`
         - (Pouze pro dodatky a objednávky) hlavní `Smlouva`
         - Očekávaná cena za:
             - Celkem
-- 
GitLab