small refactoring with more precise declarations

This commit is contained in:
2026-06-17 16:54:54 +02:00
parent f24c4f0ff7
commit decfdbffd1
2 changed files with 101 additions and 41 deletions

View File

@@ -2,7 +2,7 @@ from __future__ import annotations
import dataclasses as dc
import datetime
from typing import Any, TypedDict, cast
from typing import Any, TypeAlias, TypedDict, cast
import polars as pl
import sqlalchemy as sql
@@ -10,6 +10,8 @@ import sqlalchemy as sql
from wce_crm import db
from wce_crm.logging import logger_back as logger
InitRecId: TypeAlias = int
class CompanyInfo(TypedDict):
ma_id: str
@@ -151,43 +153,63 @@ def initrec_comp_contact_person_search_get_info(
def initrec_insert_initial_recording(
data: dict[str, Any],
) -> None:
) -> InitRecId:
logger.debug("[Call backend] insert_initial_recording")
stmt = db.grunderfassung.insert().values(data)
stmt = db.grunderfassung.insert()
with db.ENGINE.begin() as conn:
conn.execute(stmt)
ret = conn.execute(stmt, data)
if ret.rowcount == 0:
raise IOError("Entry was not inserted correctly")
prim_keys = ret.inserted_primary_key
assert prim_keys
return prim_keys[0]
def initrec_update_initial_recording(
id_: int,
id_: InitRecId,
data: dict[str, Any],
) -> None:
logger.debug("[Call backend] update_initial_recording")
stmt = (
db.grunderfassung.update().where(db.grunderfassung.c.erfassung_id == id_).values(data)
)
stmt = db.grunderfassung.update().where(db.grunderfassung.c.erfassung_id == id_)
with db.ENGINE.begin() as conn:
conn.execute(stmt)
conn.execute(stmt, data)
def initrec_get_initial_recording(
id_: int,
id_: InitRecId,
) -> dict[str, Any]:
logger.debug("[Call backend] get_initial_recording")
stmt = db.grunderfassung.select().where(db.grunderfassung.c.erfassung_id == id_)
with db.ENGINE.begin() as conn:
ret = conn.execute(stmt)
row = ret.fetchone()
if row is None:
if ret.rowcount == 0:
raise KeyError(f"Database ID {id_} not found")
row = ret.fetchone()
assert row, "row was not obtained"
return row._asdict()
def initrec_delete_initial_recording(
id_: InitRecId,
) -> None:
logger.debug("[Call backend] delete_initial_recording")
stmt = db.grunderfassung.delete().where(db.grunderfassung.c.erfassung_id == id_)
with db.ENGINE.begin() as conn:
ret = conn.execute(stmt)
if ret.rowcount == 0:
raise KeyError(f"Database ID {id_} not found for deletion")
@dc.dataclass(slots=True)
class FrontpageCompany:
erfassung_id: int
erfassung_id: InitRecId
# ma_id: int
name: str
Metadaten_aktualisierung: datetime.datetime

View File

@@ -53,7 +53,7 @@ from PySide6.QtWidgets import (
)
import wce_crm.constants
from wce_crm.backend import backend as be_init_rec
from wce_crm.backend import backend
from wce_crm.data_models import COLUMN_SEP, FlatBaseModel, Grunderfassung
from wce_crm.form_defs import (
INITREC_COMP,
@@ -226,7 +226,7 @@ class AutoFormInsert(Protocol):
def __call__(
self,
data: dict[str, Any],
) -> None: ...
) -> backend.InitRecId: ...
class AutoFormUpdate(Protocol):
@@ -244,12 +244,20 @@ class AutoFormGet(Protocol):
) -> dict[str, Any]: ...
class AutoFormDelete(Protocol):
def __call__(
self,
id_: int,
) -> None: ...
@dc.dataclass(slots=True)
class AutoFormConfig:
model: type[FlatBaseModel]
data_insert: AutoFormInsert
data_update: AutoFormUpdate
data_get: AutoFormGet
data_delete: AutoFormDelete
form_fields: Sequence[FormField]
ignored_keys: Iterable[str] = tuple()
add_buttons: bool = True
@@ -1001,7 +1009,7 @@ class Grunderfassung_SuchWidget(CustomWidget):
def fill_out_company(
self,
data: be_init_rec.CompanyInfo,
data: backend.CompanyInfo,
) -> None:
for key, widget in self.company_widgets.items():
if key not in data:
@@ -1015,7 +1023,7 @@ class Grunderfassung_SuchWidget(CustomWidget):
def fill_out_person(
self,
data: be_init_rec.ContactPersonInfo,
data: backend.ContactPersonInfo,
) -> None:
for key, widget in self.person_widgets.items():
if key not in data:
@@ -1042,7 +1050,7 @@ class Grunderfassung_SuchWidget(CustomWidget):
def update_company_data(self) -> None:
self.company_search_input.clear()
self.company_search_input.addItem(DROPDOWN_DEFAULT, None)
search_choices = be_init_rec.initrec_comp_search_choices()
search_choices = backend.initrec_comp_search_choices()
for item, db_index in search_choices:
self.company_search_input.addItem(item, db_index)
self.company_search_input.setCurrentIndex(-1)
@@ -1053,7 +1061,7 @@ class Grunderfassung_SuchWidget(CustomWidget):
) -> None:
self.person_search_input.clear()
self.person_search_input.addItem(DROPDOWN_DEFAULT, None)
search_choices = be_init_rec.initrec_comp_contact_person_search_choices(ma_id, True)
search_choices = backend.initrec_comp_contact_person_search_choices(ma_id, True)
for item, db_index in search_choices:
self.person_search_input.addItem(item, db_index)
self.person_search_input.setCurrentIndex(0)
@@ -1066,7 +1074,7 @@ class Grunderfassung_SuchWidget(CustomWidget):
if ma_id is None or index == (-1):
self._clear_company_fields()
return
data = be_init_rec.initrec_comp_search_get_info(
data = backend.initrec_comp_search_get_info(
ma_id=ma_id,
)
self.fill_out_company(data)
@@ -1081,7 +1089,7 @@ class Grunderfassung_SuchWidget(CustomWidget):
self._clear_person_fields()
return
data = be_init_rec.initrec_comp_contact_person_search_get_info(
data = backend.initrec_comp_contact_person_search_get_info(
an_id=an_id,
)
self.fill_out_person(data)
@@ -1159,7 +1167,7 @@ def search_widgets_by_key(
class AutoForm(QWidget):
"""a widget, which is managed by a code-defined field definition collection"""
save_clicked_form = Signal() # formular saved (data changed for front page)
update_triggered = Signal() # formular saved (data changed for front page)
def __init__(
self,
@@ -1273,6 +1281,7 @@ class AutoForm(QWidget):
if self.add_buttons:
self.layout_btn = QHBoxLayout()
self.main_layout.addLayout(self.layout_btn)
# save
self.save_btn_txt_enabled = "Speichern (Strg + S)"
self.save_btn_txt_disabled = "Wird gespeichert..."
self.save_btn = QPushButton(self.save_btn_txt_enabled)
@@ -1283,6 +1292,7 @@ class AutoForm(QWidget):
)
self.save_btn.clicked.connect(self.save_data)
self.layout_btn.addWidget(self.save_btn)
# reset
self.reset_btn = QPushButton("Zurücksetzen (Strg + Z)")
self.reset_btn.setShortcut("Ctrl+Z")
self.reset_btn.setFixedHeight(50)
@@ -1291,6 +1301,15 @@ class AutoForm(QWidget):
)
self.reset_btn.clicked.connect(self.reset_form)
self.layout_btn.addWidget(self.reset_btn)
# delete
self.delete_btn = QPushButton("Eintrag löschen (Strg + L)")
self.delete_btn.setShortcut("Ctrl+L")
self.delete_btn.setFixedHeight(50)
self.delete_btn.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed
)
self.delete_btn.clicked.connect(self.delete_data)
self.layout_btn.addWidget(self.delete_btn)
self.current_id: int = -1
@@ -1322,6 +1341,18 @@ class AutoForm(QWidget):
QTimer.singleShot(timeout + 1, lambda: self.save_btn.setShortcut("Ctrl+S"))
self.save_btn.setText(self.save_btn_txt_enabled)
def _activation_delete(self) -> None:
if self.current_id > -1:
self.delete_btn.setEnabled(True)
else:
self.delete_btn.setEnabled(False)
def delete_data(self) -> None:
assert self.current_id > -1, "deletion initialised despite no index set"
self.cfg.data_delete(self.current_id)
self.update_triggered.emit()
self.reset_form()
def load_data(
self,
lookup_id: int | None = None,
@@ -1354,6 +1385,7 @@ class AutoForm(QWidget):
logger_auto_form.debug("Form data:\n%s", pformat(form_data))
self.set_form_data(form_data)
self.current_id = lookup_id
self._activation_delete()
def save_data(self) -> None:
self._disable_save()
@@ -1417,13 +1449,16 @@ class AutoForm(QWidget):
if self.current_id < 0:
logger_auto_form.debug("Insert triggered")
self.cfg.data_insert(db_data)
init_rec_id = self.cfg.data_insert(db_data)
assert isinstance(init_rec_id, int)
self.current_id = init_rec_id
else:
logger_auto_form.debug("Update triggered")
self.cfg.data_update(self.current_id, db_data)
logger_auto_form.info("Data saved successfully")
self.save_clicked_form.emit()
self.update_triggered.emit()
self._activation_delete()
# self.reset_form() # TODO check if this behaviour is expected
finally:
# always re-enable save, even if error occurred
@@ -1435,6 +1470,7 @@ class AutoForm(QWidget):
def reset_form(self) -> None:
reset_form(self.widget_registry)
self.current_id = -1
self._activation_delete()
def get_form_data(self) -> dict[str, Any]:
form_data = get_form_data(self.widget_registry)
@@ -1977,12 +2013,12 @@ class NoScrollFilter(QObject):
class ClickableCell(QFrame):
"""cell in the table on the startup screen"""
clicked = Signal(be_init_rec.FrontpageCompany)
clicked = Signal(backend.FrontpageCompany)
def __init__(
self,
text: str,
data_record: be_init_rec.FrontpageCompany,
data_record: backend.FrontpageCompany,
):
super().__init__()
self.data_record = data_record
@@ -2068,9 +2104,10 @@ class NewEntrySelect_view(QWidget):
CONFIG_GRUNDERFASSUNG_UNTERNEHMEN: Final[AutoFormConfig] = AutoFormConfig(
model=Grunderfassung,
data_insert=be_init_rec.initrec_insert_initial_recording,
data_update=be_init_rec.initrec_update_initial_recording,
data_get=be_init_rec.initrec_get_initial_recording,
data_insert=backend.initrec_insert_initial_recording,
data_update=backend.initrec_update_initial_recording,
data_get=backend.initrec_get_initial_recording,
data_delete=backend.initrec_delete_initial_recording,
ignored_keys=(
"Metadaten_erstellung",
"Metadaten_aktualisierung",
@@ -2081,9 +2118,10 @@ CONFIG_GRUNDERFASSUNG_UNTERNEHMEN: Final[AutoFormConfig] = AutoFormConfig(
CONFIG_GRUNDERFASSUNG_PERSONEN: Final[AutoFormConfig] = AutoFormConfig(
model=Grunderfassung,
data_insert=be_init_rec.initrec_insert_initial_recording,
data_update=be_init_rec.initrec_update_initial_recording,
data_get=be_init_rec.initrec_get_initial_recording,
data_insert=backend.initrec_insert_initial_recording,
data_update=backend.initrec_update_initial_recording,
data_get=backend.initrec_get_initial_recording,
data_delete=backend.initrec_delete_initial_recording,
ignored_keys=(
"Metadaten_erstellung",
"Metadaten_aktualisierung",
@@ -2100,7 +2138,7 @@ CUSTOM_WIDGETS: Final[dict[str, type[CustomWidget]]] = {
class Page_InitRecCompany(QWidget):
back_main_requested = Signal() # back to main page
back_requested = Signal() # back button
save_clicked_form = Signal() # form saved (data changed for front page)
update_triggered = Signal() # form saved (data changed for front page)
def __init__(self):
super().__init__()
@@ -2164,7 +2202,7 @@ class Page_InitRecCompany(QWidget):
container_layout.addSpacing(20)
self.auto_form = AutoForm(cfg=CONFIG_GRUNDERFASSUNG_UNTERNEHMEN)
container_layout.addWidget(self.auto_form)
self.auto_form.save_clicked_form.connect(lambda: self.save_clicked_form.emit())
self.auto_form.update_triggered.connect(lambda: self.update_triggered.emit())
container_layout.addSpacing(15)
@@ -2229,7 +2267,7 @@ class Page_InitRecCompany(QWidget):
class Page_InitRecPerson(QWidget):
back_main_requested = Signal() # back to main page
back_requested = Signal() # back button
save_clicked_form = Signal() # form saved (data changed for front page)
update_triggered = Signal() # form saved (data changed for front page)
def __init__(self):
super().__init__()
@@ -2293,7 +2331,7 @@ class Page_InitRecPerson(QWidget):
container_layout.addSpacing(20)
self.auto_form = AutoForm(cfg=CONFIG_GRUNDERFASSUNG_PERSONEN)
container_layout.addWidget(self.auto_form)
self.auto_form.save_clicked_form.connect(lambda: self.save_clicked_form.emit())
self.auto_form.update_triggered.connect(lambda: self.update_triggered.emit())
container_layout.addSpacing(15)
@@ -2402,13 +2440,13 @@ class MainWindow(QMainWindow):
self.initrec_company = Page_InitRecCompany()
self.initrec_company.back_main_requested.connect(self.show_main_page)
self.initrec_company.back_requested.connect(self.show_new_entry_select)
self.initrec_company.save_clicked_form.connect(self.update_grid)
self.initrec_company.update_triggered.connect(self.update_grid)
self.stack.addWidget(self.initrec_company)
# SITE: 'Grunderfassung Person'
self.initrec_person = Page_InitRecPerson()
self.initrec_person.back_main_requested.connect(self.show_main_page)
self.initrec_person.back_requested.connect(self.show_new_entry_select)
self.initrec_person.save_clicked_form.connect(self.update_grid)
self.initrec_person.update_triggered.connect(self.update_grid)
self.stack.addWidget(self.initrec_person)
def setup_main_page(self):
@@ -2505,14 +2543,14 @@ class MainWindow(QMainWindow):
def update_grid(self) -> None:
clear_layout(self.grid)
data = be_init_rec.front_get_company_list()
data = backend.front_get_company_list()
for entry in data:
self.add_row_to_grid(entry)
def add_row_to_grid(
self,
entry: be_init_rec.FrontpageCompany,
entry: backend.FrontpageCompany,
):
row = self.current_row
@@ -2546,7 +2584,7 @@ class MainWindow(QMainWindow):
def goto_initial_recording(
self,
data: be_init_rec.FrontpageCompany,
data: backend.FrontpageCompany,
):
if data.is_company:
self.initrec_company.auto_form.load_data(data.erfassung_id)