From 31ad3ebc6508190253100f2fae275e58f919e1c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <git@imaniti.org>
Date: Sun, 19 Feb 2023 15:41:31 +0100
Subject: [PATCH] wip - single contract display

---
 contracts/admin.py                            |   7 +-
 ...name_subtype_contract_subtypes_and_more.py |  29 ++++
 ...ttype_remove_contract_subtypes_and_more.py |  48 ++++++
 .../0005_rename_type_contract_types.py        |  18 +++
 .../0006_remove_contract_contains_nda.py      |  17 +++
 contracts/models.py                           |  45 ++----
 contracts/templates/contracts/index.html      |  18 ++-
 .../templates/contracts/view_contract.html    | 140 ++++++++++++++++++
 contracts/templatetags/subtract.py            |   3 +-
 contracts/urls.py                             |   1 +
 contracts/views.py                            |  16 ++
 static_src/admin/contract_form.js             |  29 ----
 12 files changed, 300 insertions(+), 71 deletions(-)
 create mode 100644 contracts/migrations/0003_rename_subtype_contract_subtypes_and_more.py
 create mode 100644 contracts/migrations/0004_contracttype_remove_contract_subtypes_and_more.py
 create mode 100644 contracts/migrations/0005_rename_type_contract_types.py
 create mode 100644 contracts/migrations/0006_remove_contract_contains_nda.py
 create mode 100644 contracts/templates/contracts/view_contract.html

diff --git a/contracts/admin.py b/contracts/admin.py
index 5c97886..448b493 100644
--- a/contracts/admin.py
+++ b/contracts/admin.py
@@ -15,7 +15,7 @@ from .models import (
     ContractFilingArea,
     ContractIntent,
     ContractIssue,
-    ContractSubtype,
+    ContractType,
     Signee,
     SigneeRepresentative,
     SigneeSignature,
@@ -55,8 +55,7 @@ class ContractAdmin(MarkdownxGuardedModelAdmin):
 
     fields = (
         "created_by",
-        "type",
-        "subtype",
+        "types",
         "valid_start_date",
         "valid_end_date",
         "legal_state",
@@ -125,7 +124,7 @@ for model in (
     ContracteeSignature,
     SigneeRepresentative,
     ContracteeRepresentative,
-    ContractSubtype,
+    ContractType,
     ContractIntent,
 ):
     admin.site.register(model, IndexHiddenModelAdmin)
diff --git a/contracts/migrations/0003_rename_subtype_contract_subtypes_and_more.py b/contracts/migrations/0003_rename_subtype_contract_subtypes_and_more.py
new file mode 100644
index 0000000..fa1788d
--- /dev/null
+++ b/contracts/migrations/0003_rename_subtype_contract_subtypes_and_more.py
@@ -0,0 +1,29 @@
+# Generated by Django 4.1.4 on 2023-02-19 12:40
+
+import colorfield.fields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contracts', '0002_remove_contract_expected_cost_hour_and_more'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='contract',
+            old_name='subtype',
+            new_name='subtypes',
+        ),
+        migrations.AlterField(
+            model_name='contractee',
+            name='color',
+            field=colorfield.fields.ColorField(blank=True, default=None, image_field=None, max_length=18, null=True, samples=None, verbose_name='Barva'),
+        ),
+        migrations.AlterField(
+            model_name='signee',
+            name='color',
+            field=colorfield.fields.ColorField(blank=True, default=None, image_field=None, max_length=18, null=True, samples=None, verbose_name='Barva'),
+        ),
+    ]
diff --git a/contracts/migrations/0004_contracttype_remove_contract_subtypes_and_more.py b/contracts/migrations/0004_contracttype_remove_contract_subtypes_and_more.py
new file mode 100644
index 0000000..1048d44
--- /dev/null
+++ b/contracts/migrations/0004_contracttype_remove_contract_subtypes_and_more.py
@@ -0,0 +1,48 @@
+# Generated by Django 4.1.4 on 2023-02-19 13:08
+
+from django.db import migrations, models
+import django.db.models.deletion
+import shared.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contracts', '0003_rename_subtype_contract_subtypes_and_more'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ContractType',
+            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')),
+            ],
+            options={
+                'verbose_name': 'Typ smlouvy',
+                'verbose_name_plural': 'Typy smlouvy',
+            },
+            bases=(shared.models.NameStrMixin, models.Model),
+        ),
+        migrations.RemoveField(
+            model_name='contract',
+            name='subtypes',
+        ),
+        migrations.AlterField(
+            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='Primární smlouva'),
+        ),
+        migrations.RemoveField(
+            model_name='contract',
+            name='type',
+        ),
+        migrations.DeleteModel(
+            name='ContractSubtype',
+        ),
+        migrations.AddField(
+            model_name='contract',
+            name='type',
+            field=models.ManyToManyField(to='contracts.contracttype', verbose_name='Typ'),
+        ),
+    ]
diff --git a/contracts/migrations/0005_rename_type_contract_types.py b/contracts/migrations/0005_rename_type_contract_types.py
new file mode 100644
index 0000000..6e55348
--- /dev/null
+++ b/contracts/migrations/0005_rename_type_contract_types.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.1.4 on 2023-02-19 13:09
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contracts', '0004_contracttype_remove_contract_subtypes_and_more'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='contract',
+            old_name='type',
+            new_name='types',
+        ),
+    ]
diff --git a/contracts/migrations/0006_remove_contract_contains_nda.py b/contracts/migrations/0006_remove_contract_contains_nda.py
new file mode 100644
index 0000000..a9a9f4d
--- /dev/null
+++ b/contracts/migrations/0006_remove_contract_contains_nda.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.1.4 on 2023-02-19 13:13
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contracts', '0005_rename_type_contract_types'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='contract',
+            name='contains_nda',
+        ),
+    ]
diff --git a/contracts/models.py b/contracts/models.py
index aa8b93c..975098f 100644
--- a/contracts/models.py
+++ b/contracts/models.py
@@ -254,15 +254,15 @@ class ContracteeRepresentative(RepresentativeMixin, models.Model):
         verbose_name_plural = "Zástupci"
 
 
-class ContractSubtype(NameStrMixin, models.Model):
+class ContractType(NameStrMixin, models.Model):
     name = models.CharField(
         max_length=32,
         verbose_name="Jméno",
     )
 
     class Meta:
-        verbose_name = "Podtyp smlouvy"
-        verbose_name_plural = "Podtypy smlouvy"
+        verbose_name = "Typ smlouvy"
+        verbose_name_plural = "Typy smlouvy"
 
 
 class ContractIssue(NameStrMixin, models.Model):
@@ -293,29 +293,11 @@ class ContractFilingArea(NameStrMixin, models.Model):
 
 
 class Contract(models.Model):
-    class ContractTypes(models.TextChoices):
-        PRIMARY = "primary", "Hlavní"
-        AMENDMENT = "amendment", "Dodatek"
-        FRAMEWORK_ORDER = "framework_order", "Objednávka u rámcové smlouvy"
-
-    type = models.CharField(
-        max_length=15,
-        choices=ContractTypes.choices,
-        default=ContractTypes.PRIMARY,
+    types = models.ManyToManyField(
+        ContractType,
         verbose_name="Typ",
     )
 
-    subtype = models.ManyToManyField(
-        ContractSubtype,
-        verbose_name="Podtypy",
-        blank=True,
-    )
-
-    contains_nda = models.BooleanField(
-        default=False,
-        verbose_name="Obsahuje NDA",
-    )
-
     all_parties_sign_date = models.DateField(
         verbose_name="Datum podpisu všech stran",
         blank=True,
@@ -354,6 +336,7 @@ class Contract(models.Model):
         STORED = "stored", "Uložená"
         TO_SHRED = "to_shred", "Ke skartaci"
         SHREDDED = "shredded", "Skartovaná"
+        LOST = "lost", "Ztracená"
 
     legal_state = models.CharField(
         max_length=13,
@@ -397,6 +380,13 @@ class Contract(models.Model):
         null=True,
         verbose_name="Odkaz na výběrové řízení",
     )
+    
+    agreement_url = models.URLField(
+        max_length=256,
+        blank=True,
+        null=True,
+        verbose_name="Odkaz na schválení",
+    )  # WARNING: Dependent on the type!
 
     identifier = models.CharField(
         max_length=128,
@@ -429,14 +419,7 @@ class Contract(models.Model):
         blank=True,
         null=True,
         related_name="subcontracts",
-        verbose_name="Hlavní smlouva",
-    )  # WARNING: Dependent on the type!
-
-    agreement_url = models.URLField(
-        max_length=256,
-        blank=True,
-        null=True,
-        verbose_name="Odkaz na schválení",
+        verbose_name="Primární smlouva",
     )  # WARNING: Dependent on the type!
 
     filing_area = models.ForeignKey(
diff --git a/contracts/templates/contracts/index.html b/contracts/templates/contracts/index.html
index f25553a..9f51d4a 100644
--- a/contracts/templates/contracts/index.html
+++ b/contracts/templates/contracts/index.html
@@ -21,28 +21,34 @@
                     <td>
                         <a
                             class="underline"
-                            href="#"
+                            href="{% url "contracts:view_contract" contract.id %}"
                         >{{ contract.identifier }}</a>
                     </td>
-                    <td>{{ contract.get_type_display }}</td>
+                    <td>
+                        <ul class="flex flex-wrap gap-1.5">
+                            {% for type in contract.types.all %}
+                                <li class="p-1.5 rounded-sm whitespace-nowrap bg-gray-200">{{ type.name }}</li>
+                            {% endfor %}
+                        </ul>
+                    </td>
                     <td>{{ contract.get_legal_state_display }}</td>
                     <td>{{ contract.valid_start_date }}</td>
                     <td>{{ contract.valid_end_date }}</td>
                     <td>
-                        <ul class="flex flex-col gap-1">
+                        <ul class="flex flex-wrap gap-1.5">
                             {% for signature in contract.contractee_signatures.all %}
                                 <li
-                                    class="p-2 rounded-sm cursor-pointer text-center {% if not signature.signee.color %}bg-gray-200 duration-100 hover:bg-gray-300{% endif %}"
+                                    class="p-1.5 rounded-sm whitespace-nowrap cursor-pointer {% if not signature.signee.color %}bg-gray-200 duration-100 hover:bg-gray-300{% endif %}"
                                     {% if signature.signee.color %}style="background-color:{{ signature.signee.color }}"{% endif %}
                                 >{{ signature.contractee.name }}</li>
                             {% endfor %}
                         </ul>
                     </td>
                     <td>
-                        <ul class="flex flex-col gap-1">
+                        <ul class="flex flex-wrap gap-1.5">
                             {% for signature in contract.signee_signatures.all %}
                                 <li
-                                    class="p-2 rounded-sm cursor-pointer text-center {% if not signature.signee.color %}bg-gray-200 duration-100 hover:bg-gray-300{% endif %}"
+                                    class="p-1.5 rounded-sm whitespace-nowrap cursor-pointer {% if not signature.signee.color %}bg-gray-200 duration-100 hover:bg-gray-300{% endif %}"
                                     {% if signature.signee.color %}style="background-color:{{ signature.signee.color }}"{% endif %}
                                 >{{ signature.signee.name }}</li>
                             {% endfor %}
diff --git a/contracts/templates/contracts/view_contract.html b/contracts/templates/contracts/view_contract.html
new file mode 100644
index 0000000..29f7c3a
--- /dev/null
+++ b/contracts/templates/contracts/view_contract.html
@@ -0,0 +1,140 @@
+{% extends "shared/includes/base.html" %}
+{% load subtract %}
+
+{% block content %}
+    <h1 class="head-alt-lg mb-10">{{ contract.identifier }}</h1>
+    
+    <h2 class="text-xl font-bold mb-5"><i class="ico--info mr-3"></i>Základní informace</h2>
+    
+    <table class="table table-auto w-full table--striped table--bordered mb-10">
+        <tbody>
+            <tr>
+                <td class="w-1/5 !p-2.5">Typy</td>
+                <td class="w-4/5 !p-2.5">
+                    <ul class="flex flex-wrap gap-1.5">
+                        {% for type in contract.types.all %}
+                            <li class="p-1.5 rounded-sm whitespace-nowrap bg-gray-200">{{ type.name }}</li>
+                        {% endfor %}
+                    </ul>
+                </td>
+            </tr>
+            <tr>
+                <td class="w-1/5 !p-2.5">Právní stav</td>
+                <td class="w-4/5 !p-2.5">{{ contract.get_legal_state_display }}</td>
+            </tr>
+            <tr>
+                <td class="w-1/5 !p-2.5">Stav papírové verze</td>
+                <td class="w-4/5 !p-2.5">{{ contract.get_paper_form_state_display }}</td>
+            </tr>
+            <tr>
+                <td class="w-1/5 !p-2.5">Výběrové řízení</td>
+                <td class="w-4/5 !p-2.5">
+                    {% if contract.tender_url %}
+                        <a
+                            class="underline"
+                            href="{{ contract.tender_url }}"
+                        >{{ contract.tender_url }}</a>
+                    {% else %}
+                        <span class="text-grey-200">Není zadáno</span>
+                    {% endif %}
+                </td>
+            </tr>
+            <tr>
+                <td class="w-1/5 !p-2.5">Schválení</td>
+                <td class="w-4/5 !p-2.5">
+                    {% if contract.agreement_url %}
+                        <a
+                            class="underline"
+                            href="{{ contract.agreement_url }}"
+                        >{{ contract.agreement_url }}</a>
+                    {% else %}
+                        <span class="text-grey-200">Není zadáno</span>
+                    {% endif %}
+                </td>
+            </tr>
+            <tr>
+                <td class="w-1/5 !p-2.5">Problémy</td>
+                <td class="w-4/5 !p-2.5">
+                    {% with contract.issues.all as issues %}
+                        {% if issues|length != 0 %}
+                            <ul class="flex gap-2">
+                                {% for issue in issues %}
+                                    <li class="p-1.5 rounded-sm bg-grey-200">{{ issue.name }}</li>
+                                {% endfor %}
+                            </ul>
+                        {% else %}
+                            <span class="text-grey-200">Žádné</span>
+                        {% endif %}
+                    {% endwith %}
+                </td>
+            </tr>
+            {% if contract.primary_contract %}
+                <tr>
+                    <td class="w-1/5 !p-2.5">Primární smlouva</td>
+                    <td class="w-4/5 !p-2.5">
+                        <a
+                            href="{% url "contracts:view_contract" contract.primary_contract.id %}"
+                        >{{ contract.primary_contract.identifier }}</a>
+                    </td>
+                </tr>
+            {% endif %}
+            <tr>
+                <td class="w-1/5 !p-2.5">Soubory</td>
+                <td class="w-4/5 !p-2.5">
+                    {% with contract.files.all as files %}
+                        {% if files|length != 0 %}
+                            <ul class="flex gap-2">
+                                {% for file in files %}
+                                    <li class="p-1.5 rounded-sm bg-gray-200">
+                                        <a
+                                            href="{{ file.file.url }}"
+                                        ><i class="ico--attachment mr-2"></i>{{ file.name }}</a>
+                                    </li>
+                                {% endfor %}
+                            </ul>
+                        {% else %}
+                            <span class="text-grey-200">Žádné</span>
+                        {% endif %}
+                    {% endwith %}
+                </td>
+            </tr>
+        </tbody>
+    </table>
+    
+    <h2 class="text-xl font-bold mb-5"><i class="ico--pencil mr-3"></i>Podpisy</h2>
+    
+    <h3 class="text-lg font-bold mb-5">Naší smluvní strany</h3>
+    
+    {% with contract.contractee_signatures.all as signatures %}
+        {% if signatures|length != 0 %}
+            <ul class="mb-5">
+                {% for signature in signatures %}
+                    <li class="py-2 {% if not forloop.last %}border-b border-grey-200{% endif %}">
+                        <address>
+                            <strong>{{ signature.contractee.name }}</strong>
+                            {% if signature.contractee.department %}
+                                - {{ signature.contractee.department }}
+                            {% endif %}<br>
+                            
+                            {{ signature.contractee.address_street_with_number }}<br>
+                            {{ signature.contractee.address_zip }} {{ signature.contractee.address_district }}<br>
+                            {{ signature.contractee.get_address_country_display }}<br>
+                            
+                            {% if signature.contractee.ico_number %}
+                                IČO: {{ signature.contractee.ico_number }}<br>
+                            {% endif %}
+                        </address>
+                    </li>
+                {% endfor %}
+            </ul>
+        {% else %}
+            <div class="mb-5 text-grey-200">Žádné podpisy.</div>
+        {% endif %}
+    {% endwith %}
+    
+    <h3 class="text-lg font-bold mb-5">Ostatních smluvní stran</h3>
+    
+    <ul>
+        
+    </ul>
+{% endblock %}
diff --git a/contracts/templatetags/subtract.py b/contracts/templatetags/subtract.py
index 076ef2c..6faf0b9 100644
--- a/contracts/templatetags/subtract.py
+++ b/contracts/templatetags/subtract.py
@@ -2,6 +2,7 @@ from django import template
 
 register = template.Library()
 
-@register.filter(name='subtract')
+
+@register.filter(name="subtract")
 def subtract(value, arg):
     return value - arg 
diff --git a/contracts/urls.py b/contracts/urls.py
index 3d6e452..e649007 100644
--- a/contracts/urls.py
+++ b/contracts/urls.py
@@ -5,4 +5,5 @@ from . import views
 app_name = "contracts"
 urlpatterns = [
     path("", views.index, name="index"),
+    path("contracts/<int:id>", views.view_contract, name="view_contract"),
 ]
diff --git a/contracts/views.py b/contracts/views.py
index 226b333..d55d154 100644
--- a/contracts/views.py
+++ b/contracts/views.py
@@ -27,3 +27,19 @@ def index(request):
             "page": page,
         }
     )
+
+
+def view_contract(request, id: int):
+    contract = Contract.objects.get(id=id)
+
+    return render(
+        request,
+        "contracts/view_contract.html",
+        {
+            "site_url": settings.SITE_URL,
+            "user": request.user,
+            "title": contract.identifier,
+            "description": "",  # TODO
+            "contract": contract,
+        }
+    )
diff --git a/static_src/admin/contract_form.js b/static_src/admin/contract_form.js
index a3672ce..edfdaf9 100644
--- a/static_src/admin/contract_form.js
+++ b/static_src/admin/contract_form.js
@@ -11,21 +11,6 @@ $(window).ready(
             )
         );
 
-        const allowedPrimaryContractValues = new Set(["amendment", "framework_order"]);
-
-        $(".field-primary_contract").
-        css(
-            "display",
-            (
-                (
-                    allowedPrimaryContractValues.has(
-                        $("#id_type").find(":selected").val()
-                    )
-                ) ?
-                "block": "none"
-            )
-        );
-
         $("#id_public_state").on(
             "change",
             event => {
@@ -39,19 +24,5 @@ $(window).ready(
                 );
             }
         );
-
-        $("#id_type").on(
-            "change",
-            event => {
-                $(".field-primary_contract").
-                css(
-                    "display",
-                    (
-                        (allowedPrimaryContractValues.has($(event.target).val())) ?
-                        "block": "none"
-                    )
-                );
-            }
-        );
     }
 );
-- 
GitLab