data loading of company profiles

This commit is contained in:
2026-06-25 16:26:38 +02:00
parent b7f45066f0
commit 76ff68cb43
3 changed files with 143 additions and 44 deletions
+8 -6
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
import dataclasses as dc
import datetime
from typing import Any, TypeAlias, TypedDict, cast
from typing import TYPE_CHECKING, Any, TypedDict, cast
import polars as pl
import sqlalchemy as sql
@@ -10,9 +10,11 @@ import sqlalchemy as sql
from wce_crm import db
from wce_crm.logging import logger_back as logger
InitRecId: TypeAlias = int
if TYPE_CHECKING:
from wce_crm.types import ExtAnId, ExtMaId, InitRecId
# // externals
class CompanyInfo(TypedDict):
ma_id: str
wce_id: str
@@ -100,7 +102,7 @@ def initrec_comp_search_choices() -> tuple[tuple[str, int], ...]:
def initrec_comp_search_get_info(
ma_id: int,
ma_id: ExtMaId,
) -> CompanyInfo:
logger.debug("[Call backend] comp_search_get_info")
df = db.DF_CRM_MASTER.filter(pl.col.ma_id == ma_id)
@@ -112,7 +114,7 @@ def initrec_comp_search_get_info(
def initrec_comp_contact_person_search_choices(
ma_id: int | None,
ma_id: ExtMaId | None,
use_both_names: bool,
) -> tuple[tuple[str, int], ...]:
# TODO no reload functionality
@@ -140,7 +142,7 @@ def initrec_comp_contact_person_search_choices(
def initrec_comp_contact_person_search_get_info(
an_id: int,
an_id: ExtAnId,
) -> ContactPersonInfo:
logger.debug("[Call backend] contact_person_search_get_info")
df = db.DF_CONTACT_PERSON.filter(pl.col.an_id == an_id)
@@ -151,6 +153,7 @@ def initrec_comp_contact_person_search_get_info(
return cast(ContactPersonInfo, df.row(0, named=True))
# // internals
def initrec_insert_initial_recording(
data: dict[str, Any],
) -> InitRecId:
@@ -210,7 +213,6 @@ def initrec_delete_initial_recording(
@dc.dataclass(slots=True)
class FrontpageCompany:
erfassung_id: InitRecId
# ma_id: int
name: str
Metadaten_aktualisierung: datetime.datetime
is_company: bool
+131 -37
View File
@@ -11,7 +11,7 @@ from collections import defaultdict
from collections.abc import Container, Iterable, Sequence
from pathlib import Path
from pprint import pformat
from typing import Any, Final, Protocol, TypeAlias, TypedDict, TypeVar, cast
from typing import TYPE_CHECKING, Any, Final, Protocol, TypeAlias, TypedDict, TypeVar, cast
from typing_extensions import override
from pydantic import (
@@ -70,6 +70,10 @@ from wce_crm.logging import (
logger_get_data,
logger_gui,
)
from wce_crm.types import ExtMaId, InitRecId
if TYPE_CHECKING:
...
K = TypeVar("K")
V = TypeVar("V")
@@ -1315,7 +1319,7 @@ class AutoForm(QWidget):
self.delete_btn.clicked.connect(self.delete_data)
self.layout_btn.addWidget(self.delete_btn)
self.current_id: int = -1
self.current_id: InitRecId = -1
logger_auto_form.debug(
"Initialised Auto Form Widget. Registry:%s",
@@ -2072,7 +2076,7 @@ class NewEntrySelect_view(QWidget):
"""view for new entry for initial recording ("Grunderfassung")"""
back_requested = Signal() # Signal back button
company_requested = Signal() # Signal "Unternehmen"
company_requested = Signal(bool) # Signal "Unternehmen" (bool: reset yes/no)
person_requested = Signal() # Signal "Individualperson"
def __init__(self):
@@ -2094,7 +2098,7 @@ class NewEntrySelect_view(QWidget):
btn_company = QPushButton("Unternehmen →")
btn_company.setFixedWidth(300)
btn_company.setFixedHeight(40)
btn_company.clicked.connect(lambda: self.company_requested.emit())
btn_company.clicked.connect(lambda: self.company_requested.emit(True))
btn_person = QPushButton("Individualperson →")
btn_person.setFixedWidth(300)
@@ -2148,7 +2152,7 @@ class Page_InitRecCompany(QWidget):
back_main_requested = Signal() # back to main page
back_requested = Signal() # back button
update_triggered = Signal() # form saved (data changed for front page)
company_profile_requested = Signal()
company_profile_requested = Signal(InitRecId)
def __init__(self):
super().__init__()
@@ -2172,7 +2176,9 @@ class Page_InitRecCompany(QWidget):
header_layout.setContentsMargins(0, 0, 0, 10)
comp_profile_btn = QPushButton("Unternehmensprofil")
comp_profile_btn.clicked.connect(lambda: self.company_profile_requested.emit())
comp_profile_btn.clicked.connect(
lambda: self.company_profile_requested.emit(self.current_id)
)
comp_profile_btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
comp_profile_btn.setMinimumWidth(250)
# comp_profile_btn.setMaximumWidth(200)
@@ -2281,6 +2287,10 @@ class Page_InitRecCompany(QWidget):
def reset_form(self) -> None:
self.auto_form.reset_form()
@property
def current_id(self) -> InitRecId:
return self.auto_form.current_id
class Page_InitRecPerson(QWidget):
back_main_requested = Signal() # back to main page
@@ -2413,12 +2423,27 @@ class Page_InitRecPerson(QWidget):
class Page_CompanyProfile(QWidget):
back_main_requested = Signal() # back to main page
back_requested = Signal() # back button
back_requested = Signal(bool) # back to init rec (bool: reset yes/no)
# TODO update should trigger something else
update_triggered = Signal() # form saved (data changed for front page)
# update_triggered = Signal() # form saved (data changed for front page)
def __init__(self):
super().__init__()
# state management
self.current_id: InitRecId = -1
self.COMPANY_FETAURES_MASTER_DATA: dict[str, str] = {
"ma_unternehmensname": "Name:",
"ma_branche": "Branche:",
"ma_strasse": "Straße:",
"ma_hausnummer": "Hausnummer:",
"ma_plz": "PLZ:",
"ma_ort": "Ort:",
"ma_website": "Webseite:",
"ma_mail": "E-Mail:",
"ma_telefonnummer": "Telefon:",
}
# Hauptlayout der Seite
outer_layout = QHBoxLayout(self)
vert_layout = QVBoxLayout()
@@ -2444,7 +2469,7 @@ class Page_CompanyProfile(QWidget):
back_btn_main.setMinimumWidth(200)
back_btn_main.setMaximumWidth(200)
back_btn_step = QPushButton("← Zurück")
back_btn_step.clicked.connect(lambda: self.back_requested.emit())
back_btn_step.clicked.connect(lambda: self.back_requested.emit(False))
back_btn_step.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
back_btn_step.setMinimumWidth(200)
back_btn_step.setMaximumWidth(200)
@@ -2521,7 +2546,8 @@ class Page_CompanyProfile(QWidget):
)
left_layout.addWidget(master_data_label)
# self.table_master_data = MasterDataTable()
self.table_master_data = MasterDataFormWidget()
default_labels = tuple(self.COMPANY_FETAURES_MASTER_DATA.values())
self.table_master_data = MasterDataFormWidget(default_labels)
left_layout.addWidget(self.table_master_data)
left_layout.addWidget(QLabel("PLATZHALTER Vermerke: Welche Notizen?"))
@@ -2575,6 +2601,7 @@ class Page_CompanyProfile(QWidget):
container_layout.addLayout(main_hor_layout)
container_layout.addStretch()
# --- STYLE ---
self.setStyleSheet("""
QFrame#Segment {
background-color: #ffffff;
@@ -2606,7 +2633,7 @@ class Page_CompanyProfile(QWidget):
# }
# """)
def set_company_name(self, name: str = "") -> None:
def set_company_name(self, name: str) -> None:
if not name:
name = self.change_title_text.text()
if not name:
@@ -2615,6 +2642,42 @@ class Page_CompanyProfile(QWidget):
txt = f"Unternehmen: {name}"
self.title_company_name.setText(txt)
def load_from_id(
self,
id_: InitRecId,
) -> None:
assert id_ is not None, "tried to load with InitRecId None"
logger_gui.debug(f"Called function to load with ID: {id_}")
if id_ < 0:
# just clear and do nothing else
logger_gui.debug("just reset with ID < 0")
self.table_master_data.reset()
self.set_company_name("")
self.current_id = id_
return
if id_ == self.current_id:
logger_gui.debug("ID did not change. Do nothing")
self.current_id = id_
return
# TODO retrieve and process data to load
init_rec = backend.initrec_get_initial_recording(id_)
ma_id = cast(ExtMaId, init_rec["Partnersuche__un_suche"])
assert ma_id is not None, "no ma_id obtained"
comp_info = backend.initrec_comp_search_get_info(ma_id)
data: dict[str, Any] = {}
for feature, value in comp_info.items():
if feature in self.COMPANY_FETAURES_MASTER_DATA:
data[self.COMPANY_FETAURES_MASTER_DATA[feature]] = value
self.table_master_data.load_data(data)
self.set_company_name(data["Name:"])
self.current_id = id_
class MasterDataTable(QWidget):
def __init__(self):
@@ -2705,8 +2768,13 @@ class MasterDataTable(QWidget):
class MasterDataFormWidget(QWidget):
def __init__(self):
def __init__(
self,
default_labels: Sequence[str],
):
super().__init__()
self.default_labels = default_labels
self.default_data = {label: None for label in self.default_labels}
# main layout
main_layout = QVBoxLayout(self)
@@ -2716,37 +2784,55 @@ class MasterDataFormWidget(QWidget):
segment_frame = QFrame()
segment_frame.setObjectName("Segment")
# form layout
form_layout = QFormLayout(segment_frame)
form_layout.setSpacing(15) # Vertikaler Abstand zwischen den Zeilen
form_layout.setLabelAlignment(Qt.AlignmentFlag.AlignLeft) # Merkmale linksbündig
self.form_layout = QFormLayout(segment_frame)
self.form_layout.setSpacing(15)
self.form_layout.setLabelAlignment(Qt.AlignmentFlag.AlignLeft)
# load data
self.load_data(form_layout)
# self.load_data()
main_layout.addWidget(segment_frame)n
main_layout.addWidget(segment_frame)
self.style_ui()
self.reset()
def load_data(self, form_layout):
daten = [
("Anwendungsname", "MyQtApp Pro"),
("Version", "2.4.1-beta"),
("Datenbank-Pfad", "/var/lib/sqlite/data.db"),
("Letzter Login", "2026-06-25 09:30"),
("Benutzer-ID", "USR-88291"),
("Verschlüsselung", "AES-256-GCM"),
]
simulated_retrieved_data = {x[0]: x[1] for x in daten}
def load_data(
self,
data: dict[str, Any],
) -> None:
self.clear_current_layout()
# daten = [
# ("Anwendungsname", "MyQtApp Pro"),
# ("Version", "2.4.1-beta"),
# ("Datenbank-Pfad", "/var/lib/sqlite/data.db"),
# ("Letzter Login", "2026-06-25 09:30"),
# ("Benutzer-ID", "USR-88291"),
# ("Verschlüsselung", "AES-256-GCM"),
# ]
# simulated_retrieved_data = {x[0]: x[1] for x in daten}
for merkmal, wert in simulated_retrieved_data.items():
lbl_merkmal = QLabel(f"{merkmal}")
lbl_merkmal.setObjectName("Merkmal")
for feature, value in data.items():
label_feature = QLabel(f"{feature}")
label_feature.setObjectName("Merkmal")
lbl_wert = QLabel(str(wert))
lbl_wert.setObjectName("Wert")
if value is None:
value = ""
lbl_wert.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
label_value = QLabel(str(value))
label_value.setObjectName("Wert")
label_value.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
form_layout.addRow(lbl_merkmal, lbl_wert)
self.form_layout.addRow(label_feature, label_value)
def clear_current_layout(self):
while self.form_layout.count() > 0:
item = self.form_layout.takeAt(0)
assert item is not None
widget = item.widget()
if widget is not None:
widget.deleteLater()
def reset(self) -> None:
self.load_data(self.default_data)
def style_ui(self):
self.setStyleSheet("""
@@ -2771,7 +2857,8 @@ class MasterDataFormWidget(QWidget):
/* Linke Spalte (Merkmale): Grau und Fett */
QLabel#Merkmal {
font-weight: bold;
color: #64748b;
/* color: #64748b; */
color: #475569;
}
/* Rechte Spalte (Werte): Dunkel und gut lesbar */
@@ -2999,7 +3086,10 @@ class MainWindow(QMainWindow):
def show_new_entry_select(self):
self.stack.setCurrentWidget(self.new_entry_select)
def show_page_initrec_company(self):
def show_page_initrec_company(self, reset: bool):
# TODO: allow for "back" on profile to sustain current view
# TODO: reset if approached from "other side" by "new entry"
if reset:
self.initrec_company.reset_form()
self.stack.setCurrentWidget(self.initrec_company)
@@ -3007,7 +3097,11 @@ class MainWindow(QMainWindow):
self.initrec_person.reset_form()
self.stack.setCurrentWidget(self.initrec_person)
def show_page_company_profile(self) -> None:
def show_page_company_profile(
self,
id_: InitRecId,
) -> None:
self.company_profile.load_from_id(id_)
self.stack.setCurrentWidget(self.company_profile)
# --- MENÜ LOGIK ---
+3
View File
@@ -5,5 +5,8 @@ from typing import TYPE_CHECKING, TypeAlias
if TYPE_CHECKING:
import polars as pl
InitRecId: TypeAlias = int
ExtMaId: TypeAlias = int
ExtAnId: TypeAlias = int
PolarsSchema: TypeAlias = dict[str, type["pl.DataType"]]