From c9a43e80f3cd77c20bccec1597660d598d24e3d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <git@imaniti.org>
Date: Fri, 30 Jun 2023 22:51:18 +0900
Subject: [PATCH] improved searching

---
 .../contracts/includes/contract_list.html     |  16 +--
 contracts/templates/contracts/search.html     |  70 +++++++---
 contracts/views.py                            | 131 +++++++++++++++---
 3 files changed, 176 insertions(+), 41 deletions(-)

diff --git a/contracts/templates/contracts/includes/contract_list.html b/contracts/templates/contracts/includes/contract_list.html
index 5ed2646..e8bcf35 100644
--- a/contracts/templates/contracts/includes/contract_list.html
+++ b/contracts/templates/contracts/includes/contract_list.html
@@ -12,9 +12,9 @@
                         </h2>
                     </a>
                     <table class="table-auto border-separate border-spacing-1.5">
-                        <tbody>
+                        <tbody class="flex flex-col gap-2">
                             <tr class="flex gap-2 justify-between items-center">
-                                <td>Typy:</td>
+                                <td class="shrink-0">Typy:</td>
                                 <td>
                                     <ul class="flex flex-wrap gap-1.5">
                                         {% for type in contract.types.all %}
@@ -26,8 +26,8 @@
                                 </td>
                             </tr>
                             <tr class="flex gap-2 justify-between items-center">
-                                <td class="pt-1.5">Účinná od:</td>
-                                <td class="pt-1.5">
+                                <td class="shrink-0">Účinná od:</td>
+                                <td>
                                     {% if contract.valid_start_date %}
                                         {{ contract.valid_start_date }}
                                     {% else %}
@@ -36,8 +36,8 @@
                                 </td>
                             </tr>
                             <tr class="flex gap-2 justify-between items-center">
-                                <td class="py-1.5">Účinná do:</td>
-                                <td class="py-1.5">
+                                <td class="shrink-0">Účinná do:</td>
+                                <td>
                                     {% if contract.valid_end_date %}
                                         {{ contract.valid_end_date }}
                                     {% else %}
@@ -46,7 +46,7 @@
                                 </td>
                             </tr>
                             <tr class="flex gap-2 justify-between items-center">
-                                <td>Platná:</td>
+                                <td class="shrink-0">Platná:</td>
                                 <td>
                                     <i
                                         class="{% if contract.is_valid %}ico--checkmark{% else %}ico--cross{% endif %}"
@@ -55,7 +55,7 @@
                                 </td>
                             </tr>
                             <tr class="flex gap-2 justify-between items-center">
-                                <td>Podpis s:</td>
+                                <td class="shrink-0">Podpis s:</td>
                                 <td>
                                     <ul class="flex flex-wrap gap-1.5">
                                         {% for signature in contract.signee_signatures.all %}
diff --git a/contracts/templates/contracts/search.html b/contracts/templates/contracts/search.html
index 1897d99..216f7b0 100644
--- a/contracts/templates/contracts/search.html
+++ b/contracts/templates/contracts/search.html
@@ -2,33 +2,71 @@
 {% load add %}
 
 {% block content %}
-    {% if not query_is_set %}
-        {% include "contracts/includes/double_heading.html" with icon="ico--search" heading="Vyhledávání" subheading="dle názvu smlouvy" %}
-    {% else %}
-        {% include "contracts/includes/double_heading.html" with icon="ico--search" heading="Vyhledávání" subheading="„"|add:query|add:"“" %}
-    {% endif %}
+    {% include "contracts/includes/double_heading.html" with icon="ico--search" heading="Vyhledávání" %}
 
-    <form method="get" class="flex justify-center mb-10">
-        <div class="flex flex-row border border-black">
+    <form method="get" class="mb-10">
+        <div class="flex flex-col gap-2">
             {% csrf_token %}
+
+            <input
+                id="name"
+                name="name"
+                class="border border-black bg-grey-150 h-10 px-4 text-lg xl:h-14 xl:px-5"
+                type="text"
+                value="{% if name %}{{ name }}{% endif %}"
+                placeholder="Název"
+                aria-label="Vyhledávací box pro název"
+            >
+
+            <input
+                id="summary"
+                name="summary"
+                class="border border-black bg-grey-150 h-10 px-4 text-lg xl:h-14 xl:px-5"
+                type="text"
+                value="{% if summary %}{{ summary }}{% endif %}"
+                placeholder="Sumarizace"
+                aria-label="Vyhledávací box pro sumarizaci"
+            >
+
             <input
-                id="q"
-                name="q"
-                class="bg-grey-150 w-56 h-10 px-4 text-lg xl:h-14 xl:px-5"
+                id="signing_party_ico_number"
+                name="signing_party_ico_number"
+                class="border border-black bg-grey-150 h-10 px-4 text-lg xl:h-14 xl:px-5"
                 type="text"
-                value="{% if query_is_set %}{{ query }}{% endif %}"
-                placeholder="Hledaný název"
-                aria-label="Vyhledávací box"
+                value="{% if signing_party_ico_number %}{{ signing_party_ico_number }}{% endif %}"
+                placeholder="IČO smluvních stran"
+                aria-label="Vyhledávací box pro IČO smluvních stran"
             >
+
+            <input
+                id="signing_party_name"
+                name="signing_party_name"
+                class="border border-black bg-grey-150 h-10 px-4 text-lg xl:h-14 xl:px-5"
+                type="text"
+                value="{% if signing_party_name %}{{ signing_party_name }}{% endif %}"
+                placeholder="Název smluvních stran"
+                aria-label="Vyhledávací box pro názvy smluvních stran"
+            >
+
+            <input
+                id="signing_party_representative_name"
+                name="signing_party_representative_name"
+                class="border border-black bg-grey-150 h-10 px-4 text-lg xl:h-14 xl:px-5"
+                type="text"
+                value="{% if signing_party_representative_name %}{{ signing_party_representative_name }}{% endif %}"
+                placeholder="Zástupce smluvních stran"
+                aria-label="Vyhledávací box pro zástupce smluvních stran"
+            >
+
             <button type="submit" class="btn text-lg">
-                <div class="btn__body h-10 w-12 min-h-0 min-w-0 xl:h-14 xl:w-14">
-                    <i class="ico--search"></i>
+                <div class="btn__body h-10 xl:h-14 flex gap-3">
+                    <i class="ico--search"></i>Hledat
                 </div>
             </button>
         </div>
     </form>
 
-    {% if query_is_set %}
+    {% if any_query_is_set %}
         {% if page|length != 0 %}
             {% include "contracts/includes/contract_list.html" with page=page paginator=paginator %}
         {% else %}
diff --git a/contracts/views.py b/contracts/views.py
index 693fca2..94a4b11 100644
--- a/contracts/views.py
+++ b/contracts/views.py
@@ -123,31 +123,128 @@ def view_contract(request, id: int):
 
 
 def search(request):
-    query = request.GET.get("q")
+    request_filter = {}
+
+    for url_parameter in (
+        "name",
+        "summary",
+        "signing_party_ico_number",
+        "signing_party_name",
+        "signing_party_representative_name",
+    ):
+        request_filter[url_parameter] = request.GET.get(url_parameter)
+
+    any_query_is_set = False
+
+    for url_parameter_key in request_filter.keys():
+        if request_filter[url_parameter_key] is None:
+            continue
+
+        if request_filter[url_parameter_key].replace(" ", "") == "":
+            request_filter[url_parameter_key] = None
+        else:
+            any_query_is_set = True
+
+    if request_filter["signing_party_ico_number"] is not None:
+        if not request_filter["signing_party_ico_number"].isnumeric():
+            raise HTTPExceptions.BAD_REQUEST
+
+        request_filter["signing_party_ico_number"] = int(
+            request_filter["signing_party_ico_number"]
+        )
+
     page = paginator = None
     title = "Vyhledávání"
 
-    # Query is defined and is more than spaces
-    query_is_set = query is not None and len(query.replace(" ", "")) != 0
+    if any_query_is_set:
+        filter = models.Q()
+        annotations = {}
 
-    if query_is_set:
-        title = f"Vyhledávání - „{query}“"
+        if request_filter["name"] is not None:
+            filter = filter & models.Q(
+                lower_name__contains=request_filter["name"].lower()
+            )
+            annotations["lower_name"] = Lower("name")
 
-        lower_query = query.lower()
+        if request_filter["summary"] is not None:
+            filter = filter & models.Q(
+                lower_summary__contains=request_filter["summary"].lower()
+            )
+            annotations["lower_summary"] = Lower("summary")
+
+        if request_filter["signing_party_ico_number"] is not None:
+            filter = filter & models.Q(
+                models.Q(
+                    contractee_signatures__contractee__ico_number=request_filter[
+                        "signing_party_ico_number"
+                    ]
+                )
+                | models.Q(
+                    signee_signatures__signee__ico_number=request_filter[
+                        "signing_party_ico_number"
+                    ]
+                )
+            )
+
+        if request_filter["signing_party_name"] is not None:
+            filter = filter & models.Q(
+                models.Q(
+                    contractee_signatures__contractee__name_lower__contains=request_filter[
+                        "signing_party_name"
+                    ].lower()
+                )
+                | models.Q(
+                    signee_signatures__signee__name_lower__contains=request_filter[
+                        "signing_party_name"
+                    ].lower()
+                )
+            )
+
+            annotations.update(
+                {
+                    "contractee_signatures__contractee__name_lower": Lower(
+                        "contractee_signatures__contractee__name"
+                    ),
+                    "signee_signatures__signee__name_lower": Lower(
+                        "signee_signatures__signee__name"
+                    ),
+                }
+            )
+
+        if request_filter["signing_party_representative_name"] is not None:
+            filter = filter & models.Q(
+                models.Q(
+                    contractee_signatures__representatives__name_lower__contains=request_filter[
+                        "signing_party_representative_name"
+                    ].lower()
+                )
+                | models.Q(
+                    signee_signatures__representatives__name_lower__contains=request_filter[
+                        "signing_party_representative_name"
+                    ].lower()
+                )
+            )
+
+            annotations.update(
+                {
+                    "contractee_signatures__representatives__name_lower": Lower(
+                        "contractee_signatures__representatives__name"
+                    ),
+                    "signee_signatures__representatives__name_lower": Lower(
+                        "signee_signatures__representatives__name"
+                    ),
+                }
+            )
 
         # WARNING: PostgreSQL-dependent
         page, paginator = get_paginated_contracts(
             request,
-            (
-                models.Q(lower_name__contains=lower_query)
-                | models.Q(lower_summary__contains=lower_query)
-            ),
-            {
-                "lower_name": Lower("name"),
-                "lower_summary": Lower("summary"),
-            },
+            filter,
+            annotations,
         )
 
+        print(filter)
+
     return render(
         request,
         "contracts/search.html",
@@ -157,8 +254,8 @@ def search(request):
             "description": "",
             "page": page,
             "paginator": paginator,
-            "query": query,
-            "query_is_set": query_is_set,
+            "any_query_is_set": any_query_is_set,
+            **request_filter,
         },
     )
 
@@ -364,7 +461,7 @@ def view_contractees(request):
     contractees = get_objects_for_user(
         request.user,
         "contracts.view_contractee",
-    ).order_by("name")
+    ).order_by("name", "department")
 
     page, paginator = get_pagination(request, contractees)
 
-- 
GitLab