Sfoglia il codice sorgente

Abfrage angepasst, neue Schriftart, Modal für PDF

Co-authored-by: Copilot <copilot@github.com>
gc-server3 6 giorni fa
parent
commit
5a81b02b24

+ 5 - 5
app/query_filter.py

@@ -1,5 +1,5 @@
 import csv
-from dataclasses import dataclass
+from dataclasses import dataclass, field
 
 
 @dataclass
@@ -13,7 +13,7 @@ class FilterConfig:
     sort_column: str
     visible: bool = True
     default_value: str = ""
-    options: list[dict[str, str]] | None = None
+    options: dict[str, str] | None = field(default_factory=dict)
     current_value: str | None = None
 
     @property
@@ -25,11 +25,11 @@ class FilterConfig:
 
         if self.filter_type == "date":
             if "bis" in self.name.lower():
-                return f" [{self.key_column}] <= '{self.current_value}' "
-            return f" [{self.key_column}] >= '{self.current_value}' "
+                return f" F.[{self.key_column}] <= '{self.current_value}' "
+            return f" F.[{self.key_column}] >= '{self.current_value}' "
         # if self.filter_type == "select":
         #     return f"{self.key_column} IN ({self.current_value})"
-        return f" [{self.key_column}] LIKE '%{self.current_value}%' "
+        return f" F.[{self.key_column}] LIKE '%{self.current_value}%' "
 
     @staticmethod
     def from_dict(

+ 13 - 7
app/routes.py

@@ -59,11 +59,10 @@ def single_quote(text: str):
     return "'" + unquote(text) + "'"
 
 
-forderung_filter_config = import_filter_config("forderungen")
-
-
 @router.get("/app/forderungen/liste", response_class=HTMLResponse)
 def forderungen_liste(request: Request, db: Session = Depends(get_session), limit: int = 100, page: int = 0):
+    forderung_filter_config = import_filter_config("forderungen")
+
     params = {
         f.name: request.query_params[f.name]
         for f in forderung_filter_config
@@ -75,6 +74,8 @@ def forderungen_liste(request: Request, db: Session = Depends(get_session), limi
     context = {}
     for f in forderung_filter_config:
         context[f.name] = {filter_type_option[f.filter_type]: single_quote(params.get(f.name, f.default_value))}
+        if f.name in params:
+            f.current_value = params[f.name]
 
     query = templates.TemplateResponse(request, "forderungen/liste/queries/forderungen_liste.sql", context).body.decode(
         "utf-8"
@@ -97,17 +98,22 @@ def forderungen_liste(request: Request, db: Session = Depends(get_session), limi
             continue
         filter_temp = [
             (
-                row[col_names.index(f.sort_column)],
+                row[col_names.index(f.sort_column)] or "",
                 row[col_names.index(f.key_column)],
                 row[col_names.index(f.value_column)],
             )
             for row in q
         ]
-        filters[f.name] = {item[1]: item[2] for item in sorted(list(set(filter_temp)))}
+        if filter_temp:
+            print(filter_temp[0])
+            filters[f.name] = {item[1]: item[2] for item in sorted(list(set(filter_temp)))}
+        else:
+            print(f"Filter {f.name} has no options, skipping")
+            filters[f.name] = {}
         f.options = filters[f.name]
 
     summary = {
-        "offen": sum([r[col_names.index("offen")] for r in q]),
+        "Beleg_offen": sum([r[col_names.index("Beleg_offen")] for r in q]),
         "Anzahl": len(q),
     }
 
@@ -162,7 +168,7 @@ def forderungen_details(request: Request, primary_key: str, db: Session = Depend
         "auftraege_positionen",
         "forderungen_buchungen",
         "forderungen_kommentar",
-        "forderungen_kopf",
+        "forderungen_details",
         "forderungen_mahnungen",
         "versicherungen",
     ]:

+ 17 - 1
static/assets/css/main.css

@@ -1,3 +1,13 @@
+
+.inter-gc {
+  font-family: "Inter", sans-serif;
+  font-optical-sizing: auto;
+  font-weight: 400;
+  font-style: normal;
+}
+
+
+
 :root {
     --primary: #5468FF;
     --primary-light: #8590FF;
@@ -885,4 +895,10 @@ a {
         .send-btn:hover {
             background-color: var(--primary-light);
             transform: scale(1.05);
-        }
+        }
+
+.modal {
+    --cui-modal-width: 80%;
+}
+
+

+ 28 - 28
static/assets/css/redesign.css

@@ -31,7 +31,7 @@
   body {
     overflow-y: auto;
     overflow-x: auto;
-    font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+    font-family: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
   }
   
   /* App Shell */
@@ -734,91 +734,91 @@
   }
   
   /* Aktion */
-  .gc-table th:nth-child(1),
-  .gc-table td:nth-child(1) {
+  .gc-table th:nth-child(13),
+  .gc-table td:nth-child(13) {
     width: 54px;
   }
   
   /* Filiale / Bereich */
-  .gc-table th:nth-child(2),
-  .gc-table td:nth-child(2) {
+  .gc-table th:nth-child(1),
+  .gc-table td:nth-child(1) {
     width: 115px;
     max-width: 115px;
     white-space: normal !important;
   }
   
   /* Kunde */
-  .gc-table th:nth-child(3),
-  .gc-table td:nth-child(3) {
+  .gc-table th:nth-child(2),
+  .gc-table td:nth-child(2) {
     width: 230px;
     min-width: 230px;
     padding-left: 8px !important;
   }
   
   /* Verursacher */
-  .gc-table th:nth-child(4),
-  .gc-table td:nth-child(4) {
+  .gc-table th:nth-child(3),
+  .gc-table td:nth-child(3) {
     width: 145px;
     min-width: 145px;
     padding-left: 6px !important;
   }
   
   /* RG-Nr. */
-  .gc-table th:nth-child(5),
-  .gc-table td:nth-child(5) {
+  .gc-table th:nth-child(4),
+  .gc-table td:nth-child(4) {
     width: 118px;
   }
   
   /* RG-Datum / Fällig */
-  .gc-table th:nth-child(6),
-  .gc-table td:nth-child(6) {
+  .gc-table th:nth-child(5),
+  .gc-table td:nth-child(5) {
     width: 120px;
   }
   
   /* RG-Betrag */
-  .gc-table th:nth-child(7),
-  .gc-table td:nth-child(7) {
+  .gc-table th:nth-child(6),
+  .gc-table td:nth-child(6) {
     width: 105px;
   }
   
   /* offen / Kunde ges. */
-  .gc-table th:nth-child(8),
-  .gc-table td:nth-child(8) {
+  .gc-table th:nth-child(7),
+  .gc-table td:nth-child(7) {
     width: 155px;
   }
   
   /* Mahnstufe / Staffel */
-  .gc-table th:nth-child(9),
-  .gc-table td:nth-child(9) {
+  .gc-table th:nth-child(8),
+  .gc-table td:nth-child(8) {
     width: 125px;
   }
   
   /* Abw. */
-  .gc-table th:nth-child(10),
-  .gc-table td:nth-child(10) {
+  .gc-table th:nth-child(9),
+  .gc-table td:nth-child(9) {
     width: 80px;
   }
   
   /* Kommentar Fibu */
-  .gc-table th:nth-child(11),
-  .gc-table td:nth-child(11) {
+  .gc-table th:nth-child(10),
+  .gc-table td:nth-child(10) {
     width: 165px;
   }
   
   /* Kommentar Abteilung */
-  .gc-table th:nth-child(12),
-  .gc-table td:nth-child(12) {
+  .gc-table th:nth-child(11),
+  .gc-table td:nth-child(11) {
     width: 165px;
   }
   
   /* Wiedervorlage */
-  .gc-table th:nth-child(13),
-  .gc-table td:nth-child(13) {
+  .gc-table th:nth-child(12),
+  .gc-table td:nth-child(12) {
     width: 120px;
   }
   
   /* Abw. wieder im alten Gelb */
-  .gc-table td:nth-child(10) .gc-badge-warning {
+  .gc-table td:nth-child(9) .gc-badge-warning {
     background: #fef3c7 !important;
     color: #92400e !important;
     border-color: #fde68a !important;

BIN
static/assets/pdf/invoice.pdf


+ 5 - 1
templates/base/base.html

@@ -18,6 +18,10 @@
   <script src="https://cdn.jsdelivr.net/npm/@coreui/icons@3.0.1/dist/cjs/index.min.js"></script>
   <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
 
+  <link rel="preconnect" href="https://fonts.googleapis.com">
+  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+  <link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" rel="stylesheet">
+
   <link href="/static/assets/css/main.css" rel="stylesheet">
   <link href="/static/assets/css/redesign.css" rel="stylesheet">
 
@@ -165,7 +169,7 @@
           {% endfor %}
         </div>
         <div class="col-sm-3 text-end">
-          Gesamt: <strong>{{ summary.offen|number_format }}</strong>
+          Gesamt: <strong>{{ summary.Beleg_offen|number_format }}</strong>
         </div>
       </div>
     </div>

+ 2 - 2
templates/base/chat_container.html

@@ -10,7 +10,7 @@
                 </svg>
             </div>
             <div class="course-info">
-                <div class="course-title">{{ forderungen_kopf[0].Kunde }} / {{ forderungen_kopf[0].Beleg_Nr }}</div>
+                <div class="course-title">{{ forderungen_details[0].Kunde }} / {{ forderungen_details[0].Beleg_Nr }}</div>
                 <div class="course-participants">4 Mitarbeiter involviert</div>
             </div>
         </div>
@@ -49,7 +49,7 @@
     <div class="chat-content" id="chatContent">
         <div class="date-divider">
             <div class="divider-line"></div>
-            <div class="divider-text">{{ forderungen_kopf[0].Beleg_Datum|date_format }}</div>
+            <div class="divider-text">{{ forderungen_details[0].Beleg_Datum|date_format }}</div>
             <div class="divider-line"></div>
         </div>
         <!--

+ 22 - 0
templates/base/liste.html

@@ -61,4 +61,26 @@ Klassen:
   </table>
 </div>
 
+<!-- Modal -->
+<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h5 class="modal-title" id="exampleModalLabel">Invoice</h5>
+        <button type="button" class="btn-close" data-coreui-dismiss="modal" aria-label="Close"></button>
+      </div>
+      <div class="modal-body">
+        <iframe src="/static/assets/pdf/invoice.pdf" style="width: 100%; height: 800px;" frameborder="0">
+          Ihr Browser kann leider keine eingebetteten Frames anzeigen.
+        </iframe>
+      </div>
+      <!--
+      <div class="modal-footer">
+        <button type="button" class="btn btn-secondary" data-coreui-dismiss="modal">Schließen</button>
+      </div>
+      -->
+    </div>
+  </div>
+</div>
+
 {% endblock %}

+ 1 - 1
templates/forderungen/details/details.html

@@ -2,7 +2,7 @@
 {% block content %}
 
 <br>
-<h2>{{forderungen_kopf[0].Beleg_Text }}</h2>
+<h2>{{forderungen_details[0].Beleg_Text }}</h2>
 <br>
 
 <div class="row g-3">

+ 1 - 1
templates/forderungen/details/details_formular.html

@@ -1,4 +1,4 @@
-{% set row = forderungen_kopf[0] %}
+{% set row = forderungen_details[0] %}
 
 <form class="row g-3">
   <input type="hidden" name="source" value="details" />

+ 1 - 1
templates/forderungen/details/details_positionen.html

@@ -1,7 +1,7 @@
 <table class="table table-bordered">
     <thead>
         <tr>
-            <th>Auftrag_Position</th>
+            <th>Position</th>
             <th>Betrag</th>
         </tr>
     </thead>

+ 3 - 3
templates/forderungen/details/details_rohdaten.html

@@ -1,19 +1,19 @@
 <table class="table table-striped table-bordered">
     <div>
         <!--
-          {% for row in forderungen_kopf %}
+          {% for row in forderungen_details %}
 
             {% for key, value in row._asdict().items() %}
             <tr>
               <td><strong>{{ key }}:</strong></td>
-              <td>{{ '{{' }}forderungen_kopf[0].{{ key }} {{ '}}' }}</td>
+              <td>{{ '{{' }}forderungen_details[0].{{ key }} {{ '}}' }}</td>
             </tr>
             {% endfor %}
             {% endfor %}
           -->
     </div>
     <tbody>
-        {% for row in forderungen_kopf %}
+        {% for row in forderungen_details %}
 
         {% for key, value in row._asdict().items() %}
         <tr>

+ 5 - 5
templates/forderungen/details/details_uebersicht.html

@@ -1,4 +1,4 @@
-{% set row = forderungen_kopf[0] %}
+{% set row = forderungen_details[0] %}
 
 <div class="row mb-3">
   <div>
@@ -17,12 +17,12 @@
       </tr>
       <tr>
         <td><strong>Benutzer:</strong></td>
-        <td>{{row.User_ID }}</td>
+        <td>{{row.Benutzer_ID }}</td>
       </tr>
 
       <tr>
         <td><strong>Verursacher:</strong></td>
-        <td>{{row.Verursacher }}</td>
+        <td>{{row.Verursacher_Text }}</td>
       </tr>
 
       <tr>
@@ -83,12 +83,12 @@
 
       <tr>
         <td><strong>Tage:</strong></td>
-        <td>{{row.Tage }}</td>
+        <td>{{row.Beleg_Tage_offen }}</td>
       </tr>
 
       <tr>
         <td><strong>Staffel:</strong></td>
-        <td>{{row.Staffel }}</td>
+        <td>{{row.Staffel_Text }}</td>
       </tr>
 
       <tr>

+ 0 - 0
templates/forderungen/details/queries/forderungen_kopf.sql → templates/forderungen/details/queries/forderungen_details.sql


+ 6 - 6
templates/forderungen/liste/config/liste_filter.csv

@@ -2,16 +2,16 @@ Name;Filter_Typ;Breite;Beschriftung;Tabellenfeld;Anzeigewert;Sortierung;Standard
 Hauptbetrieb;select;2;;Client_DB;Hauptbetrieb_Name;;
 Standort;select;3;;Standort_ID;Standort_Name;;
 Bereich;select;3;;;;;
-Verursacher;select;4;;;;;
+Verursacher;select;4;;Verursacher_Text;;;
 Rechnungsnummer;text;2;;Beleg_Nr;;;
-RechnungsdatumVon;date;2;Rechnungsdatum von;Invoice_Date;;;
-RechnungsdatumBis;date;2;Rechnungsdatum bis;Invoice_Date;;;
-Kunde;text;4;;;;;
+RechnungsdatumVon;date;2;Rechnungsdatum von;Beleg_Datum;;;
+RechnungsdatumBis;date;2;Rechnungsdatum bis;Beleg_Datum;;;
+Kunde;text;4;;Kunde_Text;;;
 Abwarten;select;2;;;;;
 WiedervorlageVon;date;2;Wiedervorlage von;Wiedervorlage;;;
 WiedervorlageBis;date;2;Wiedervorlage bis;Wiedervorlage;;;
-Fahrzeug;select;2;;VIN;;;
-Staffel;select;2;;;;;
+Fahrzeug;select;2;;Fahrzeug_Nr;;;
+Staffel;select;2;;Staffel_Text;;;
 Mahnstufe;select;2;;;;;
 Bearbeitet;select;2;;;;;
 BenutzerSelect;hidden;2;Benutzer;;;;winter

+ 1 - 1
templates/forderungen/liste/liste_kopfzeile.html

@@ -1,5 +1,4 @@
     <tr>
-        <th></th>
         <th>Filiale / Bereich</th>
         <th>Kunde</th>
         <th>Verursacher</th>
@@ -12,4 +11,5 @@
         <th>Kommentar<br>Fibu</th>
         <th>Kommentar<br>Abteilung</th>
         <th>Wieder-<br>vorlage</th>
+        <th></th>
     </tr>

+ 21 - 19
templates/forderungen/liste/liste_zeile.html

@@ -1,22 +1,15 @@
 <tr>
-  <td>
-    <a href="/app/forderungen/details/{{ row.Client_DB }}_{{ row.Beleg_Nr }}"
-      class="btn btn-sm btn-primary gc-action-btn">
-      <i class="icon cil-pencil"></i>
-    </a>
-  </td>
-
   <td>
     <div class="gc-title">{{ row.Standort_Name }}</div>
     <div class="gc-subtitle">{{ row.Bereich }}</div>
   </td>
 
   <td class="gc-main-cell">
-    <a class="gc-title text-decoration-none" href="/app/forderungen/liste?Kunde={{ row.Kunde|urlencode }}">
-      {{ row.Kunde }}
+    <a class="gc-title text-decoration-none" href="/app/forderungen/liste?Kunde={{ row.Kunde_Text|urlencode }}">
+      {{ row.Kunde_Text }}
     </a>
     <div class="gc-subtitle">
-      {{ row.Kunde2 or '' }}
+      {{ row.Besitzer_Kunde_Text or '' }}
       {% if row.Kunde_Email %}
       · <a href="mailto:{{ row.Kunde_Email }}?subject={{ row.Beleg_Nr }}" hx-disable="true">E-Mail</a>
       {% endif %}
@@ -24,21 +17,23 @@
   </td>
 
   <td>
-    <a href="/app/forderungen/liste?Verursacher={{ row.Verursacher|urlencode }}"
+    <a href="/app/forderungen/liste?Verursacher={{ row.Verursacher_Text|urlencode }}"
       class="text-decoration-none fw-semibold">
-      {{ row.Verursacher }}
+      {{ row.Verursacher_Text }}
     </a>
-    {% if row.Verursacher == 'N.N.' %}
+    {% if row.Verursacher_Text == 'N.N.' %}
     <span class="gc-badge gc-badge-warning ms-1">offen</span>
     {% endif %}
   </td>
 
   <td>
-    <span class="gc-badge gc-badge-info">{{ row.Beleg_Nr }}</span>
+    <a href="#" data-coreui-toggle="modal" data-coreui-target="#exampleModal">
+      <span class="gc-badge gc-badge-info">{{ row.Beleg_Nr }}</span>
+    </a>
   </td>
 
   <td>
-    <div>{{ row.Invoice_Date|date_format }}</div>
+    <div>{{ row.Beleg_Datum|date_format }}</div>
     <div class="gc-subtitle">fällig {{ row.Fällig_Datum|date_format }}</div>
   </td>
 
@@ -47,19 +42,19 @@
   </td>
 
   <td class="text-end">
-    <div class="gc-money">{{ row.offen|number_format }} €</div>
-    <div class="gc-subtitle">{{ row.Kunde_gesamt_Bezug }} {{ row.offen_Kunde_gesamt|number_format }} €</div>
+    <div class="gc-money">{{ row.Beleg_offen|number_format }} €</div>
+    <div class="gc-subtitle">{{ row.Kunde_gesamt_Bezug }} {{ row.Kunde_offen_gesamt|number_format }} €</div>
   </td>
 
   <td class="text-end">
-    {% set mahnstufe = row.Mahnstufe or row.Stufe %}
+    {% set mahnstufe = row.Mahnstufe or '0' %}
 
     {% if mahnstufe and mahnstufe|string != '0' %}
     <span class="gc-badge gc-badge-danger gc-mahnstufe-{{ mahnstufe }}">
       M{{ mahnstufe }}
     </span>
     {% endif %}
-    <div class="gc-subtitle">{{ row.Tage }} Tage</div>
+    <div class="gc-subtitle">{{ row.Beleg_Tage_offen }} Tage</div>
   </td>
 
   <td class="text-end">
@@ -81,4 +76,11 @@
     <span class="gc-badge gc-badge-success">{{ row.Wiedervorlage|date_format }}</span>
     {% endif %}
   </td>
+
+  <td>
+    <a href="/app/forderungen/details/{{ row.Client_DB }}_{{ row.Beleg_Nr }}"
+      class="btn btn-sm btn-primary gc-action-btn">
+      <i class="icon cil-pencil"></i>
+    </a>
+  </td>
 </tr>

+ 20 - 20
templates/forderungen/liste/queries/forderungen_liste.sql

@@ -7,36 +7,36 @@ SELECT [F].[Client_DB]
      , [F].[Standort_Name]
      , [F].[Beleg_Nr]
      , [F].[Rechnung_Gutschrift]
-     , [F].[User_ID]
-     , [F].[VIN]
-     , [F].[Comment]
-     , [F].[offen]
-     , [F].[offen_Kunde_gesamt]
-     , [F].[Invoice_Date]
-     , [F].[Verursacher]
-     , [F].[Kunde]
-     , [F].[Beleg]
+     , [F].[Benutzer_ID]
+     , [F].[Fahrzeug_Nr]
+     , [F].[Beleg_Kommentar]
+     , [F].[Beleg_offen]
+     , [F].[Kunde_offen_gesamt]
+     , [F].[Beleg_Datum]
+     , [F].[Verursacher_Text]
+     , [F].[Kunde_Text]
+     , [F].[Beleg_Text]
      , [F].[Bereich]
-     , [F].[Tage]
+     , [F].[Beleg_Tage_offen]
      , CASE
-           WHEN [F].[Tage] > 90 THEN 3
-           WHEN [F].[Tage] > 60 THEN 2
-           WHEN [F].[Tage] > 30 THEN 1
+           WHEN [F].[Beleg_Tage_offen] > 90 THEN 3
+           WHEN [F].[Beleg_Tage_offen] > 60 THEN 2
+           WHEN [F].[Beleg_Tage_offen] > 30 THEN 1
            ELSE 0
        END AS [Stufe]
-     , replace([F].[Staffel], 'Wochen', 'W.') AS [Staffel]
+     , replace([F].[Staffel_Text], 'Wochen', 'W.') AS [Staffel]
      , [F].[Mahnstufe]
      , [F].[Forderungsart]
      --, [F].[Abwarten]
      , [F].[Verursacher_Benutzer_ID]
-     , F.Kunde2
-     , F.Beleg_Betrag
-     , F.Kunde_gesamt_Bezug
+     , F.[Besitzer_Kunde_Text]
+     , F.[Beleg_Betrag]
+     , F.[Kunde_gesamt_Bezug]
 
      , left(isnull([FK].[Kommentar_Fibu], ''), 50) AS [Kommentar_Fibu]
      , left(isnull([FK].[Kommentar_Abteilung], ''), 50) AS [Kommentar_Abteilung]
      , [K].[Kunde_Email] AS [Kunde_Email]
-     , coalesce([FD].[Wiedervorlage], dateadd(DAY, 14, [F].[Invoice_Date])) AS [Wiedervorlage]
+     , coalesce([FD].[Wiedervorlage], dateadd(DAY, 14, [F].[Beleg_Datum])) AS [Wiedervorlage]
      , CASE
            WHEN [FD].[Reklamation] = 'J' THEN 'Rekl.'
            WHEN [FD].[Versicherung] = 'J' THEN 'Vers.'
@@ -46,7 +46,7 @@ SELECT [F].[Client_DB]
        END AS [Abwarten]
      , isnull([FK].[Begründung], '') AS [Begründung]
      , isnull([FD].[Bearbeitet], 'N') AS [Bearbeitet]
-     , dateadd(DAY, 14, [F].[Invoice_Date]) AS [Fällig_Datum]
+     , dateadd(DAY, 14, [F].[Beleg_Datum]) AS [Fällig_Datum]
 
 FROM [dbo].[Forderungen_Kopf] [F]
          LEFT JOIN [dbo].[Kunden] [K] ON [F].[Kunde_Nr] = [K].[Kunde_Nr] AND [F].[Client_DB] = [K].[Client_DB]
@@ -60,4 +60,4 @@ AND [F].[Standort_ID] = [BR].[Standort_ID]
 AND ([BR].[Rolle] = 'Buchhaltung' OR [BR].[Benutzer_ID] = [F].[Verursacher_Benutzer_ID])
 
 WHERE 1 = 1
-ORDER BY F.[Wiedervorlage] ASC, F.[Tage] DESC
+ORDER BY F.[Wiedervorlage] ASC, F.[Beleg_Tage_offen] DESC