Dev #7

Merged
foefl merged 74 commits from dev into main 2026-07-31 14:19:01 +00:00
3 changed files with 97 additions and 66 deletions
Showing only changes of commit c1ba3cf6e7 - Show all commits
+11 -14
View File
@@ -14,7 +14,7 @@ from wce_crm.constants import TIMEZONE_CEST
from wce_crm.data_models import ( from wce_crm.data_models import (
Beratungsgespraech_Einzelgespraech, Beratungsgespraech_Einzelgespraech,
Beratungsgespraech_Vorgang, Beratungsgespraech_Vorgang,
Initrec_FromDb, Initrec,
) )
from wce_crm.logging import logger_back as logger from wce_crm.logging import logger_back as logger
from wce_crm.types import ( from wce_crm.types import (
@@ -28,7 +28,6 @@ from wce_crm.types import (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from wce_crm.data_models import AutoForm_State, Initrec
from wce_crm.types import ConsId, ExtAnId, ExtMaId, RecId from wce_crm.types import ConsId, ExtAnId, ExtMaId, RecId
@@ -153,7 +152,7 @@ def initrec_company_to_db(
) -> Initrec: ) -> Initrec:
logger.debug("[AutoForm -- backend] Call database saving routine...") logger.debug("[AutoForm -- backend] Call database saving routine...")
dump_data = copy.deepcopy(auto_form_data.form_data) dump_data = copy.deepcopy(auto_form_data.db_data)
dump_data["geloescht"] = auto_form_data.geloescht dump_data["geloescht"] = auto_form_data.geloescht
with db.ENGINE.begin() as conn: with db.ENGINE.begin() as conn:
@@ -174,7 +173,7 @@ def initrec_company_to_db(
data_from_db = from_db[0] data_from_db = from_db[0]
auto_form_data.rec_id = data_from_db["un_id"] auto_form_data.rec_id = data_from_db["un_id"]
auto_form_data.geloescht = data_from_db["geloescht"] auto_form_data.geloescht = data_from_db["geloescht"]
auto_form_data.form_data["Metadaten_aktualisierung"] = data_from_db[ auto_form_data.db_data["Metadaten_aktualisierung"] = data_from_db[
"Metadaten_aktualisierung" "Metadaten_aktualisierung"
] ]
@@ -183,7 +182,7 @@ def initrec_company_to_db(
else: else:
logger.debug("[AutoForm -- backend] Update...") logger.debug("[AutoForm -- backend] Update...")
stmt = ( stmt = (
db.beratung_vorgang.update() db.grunderfassung_unternehmen.update()
.where(db.grunderfassung_unternehmen.c.un_id == auto_form_data.rec_id) .where(db.grunderfassung_unternehmen.c.un_id == auto_form_data.rec_id)
.returning( .returning(
db.grunderfassung_unternehmen.c.Metadaten_aktualisierung, db.grunderfassung_unternehmen.c.Metadaten_aktualisierung,
@@ -196,8 +195,7 @@ def initrec_company_to_db(
assert len(from_db) == 1, "expected excatly one returned row" assert len(from_db) == 1, "expected excatly one returned row"
data_from_db = from_db[0] data_from_db = from_db[0]
auto_form_data.geloescht = data_from_db["geloescht"] auto_form_data.db_data["Metadaten_aktualisierung"] = data_from_db[
auto_form_data.form_data["Metadaten_aktualisierung"] = data_from_db[
"Metadaten_aktualisierung" "Metadaten_aktualisierung"
] ]
@@ -229,7 +227,7 @@ def initrec_company_from_db(
return Initrec( return Initrec(
rec_id=id_, rec_id=id_,
geloescht=geloescht, geloescht=geloescht,
form_data=data_from_db, db_data=data_from_db,
) )
@@ -238,7 +236,7 @@ def initrec_person_to_db(
) -> Initrec: ) -> Initrec:
logger.debug("[AutoForm -- backend] Call database saving routine...") logger.debug("[AutoForm -- backend] Call database saving routine...")
dump_data = copy.deepcopy(auto_form_data.form_data) dump_data = copy.deepcopy(auto_form_data.db_data)
dump_data["geloescht"] = auto_form_data.geloescht dump_data["geloescht"] = auto_form_data.geloescht
with db.ENGINE.begin() as conn: with db.ENGINE.begin() as conn:
@@ -259,7 +257,7 @@ def initrec_person_to_db(
data_from_db = from_db[0] data_from_db = from_db[0]
auto_form_data.rec_id = data_from_db["un_id"] auto_form_data.rec_id = data_from_db["un_id"]
auto_form_data.geloescht = data_from_db["geloescht"] auto_form_data.geloescht = data_from_db["geloescht"]
auto_form_data.form_data["Metadaten_aktualisierung"] = data_from_db[ auto_form_data.db_data["Metadaten_aktualisierung"] = data_from_db[
"Metadaten_aktualisierung" "Metadaten_aktualisierung"
] ]
@@ -268,7 +266,7 @@ def initrec_person_to_db(
else: else:
logger.debug("[AutoForm -- backend] Update...") logger.debug("[AutoForm -- backend] Update...")
stmt = ( stmt = (
db.beratung_vorgang.update() db.grunderfassung_personen.update()
.where(db.grunderfassung_personen.c.pers_id == auto_form_data.rec_id) .where(db.grunderfassung_personen.c.pers_id == auto_form_data.rec_id)
.returning( .returning(
db.grunderfassung_personen.c.Metadaten_aktualisierung, db.grunderfassung_personen.c.Metadaten_aktualisierung,
@@ -281,8 +279,7 @@ def initrec_person_to_db(
assert len(from_db) == 1, "expected excatly one returned row" assert len(from_db) == 1, "expected excatly one returned row"
data_from_db = from_db[0] data_from_db = from_db[0]
auto_form_data.geloescht = data_from_db["geloescht"] auto_form_data.db_data["Metadaten_aktualisierung"] = data_from_db[
auto_form_data.form_data["Metadaten_aktualisierung"] = data_from_db[
"Metadaten_aktualisierung" "Metadaten_aktualisierung"
] ]
@@ -314,7 +311,7 @@ def initrec_person_from_db(
return Initrec( return Initrec(
rec_id=id_, rec_id=id_,
geloescht=geloescht, geloescht=geloescht,
form_data=data_from_db, db_data=data_from_db,
) )
+10 -10
View File
@@ -225,10 +225,10 @@ class AutoFormConfig:
model: type[FlatBaseModel] model: type[FlatBaseModel]
to_db: AutoFormToDb to_db: AutoFormToDb
from_db: AutoFormFromDb from_db: AutoFormFromDb
data_insert: AutoFormInsert # data_insert: AutoFormInsert
data_update: AutoFormUpdate # data_update: AutoFormUpdate
data_get: AutoFormGet # data_get: AutoFormGet
data_delete: AutoFormDelete # data_delete: AutoFormDelete
form_fields: Sequence[FormField] form_fields: Sequence[FormField]
ignored_keys: Iterable[str] = tuple() ignored_keys: Iterable[str] = tuple()
add_buttons: bool = True add_buttons: bool = True
@@ -412,17 +412,17 @@ class FlatBaseModel(BaseModel):
# ** InitRec # ** InitRec
class Initrec_FromDb(BaseModel): # class Initrec_FromDb(BaseModel):
rec_id: RecId # rec_id: RecId
geloescht: AwareDatetime | None # geloescht: AwareDatetime | None
Metadaten_aktualisierung: AwareDatetime # Metadaten_aktualisierung: AwareDatetime
form_data: dict[str, Any] # form_data: dict[str, Any]
class Initrec(BaseModel): class Initrec(BaseModel):
rec_id: RecId | None rec_id: RecId | None
geloescht: AwareDatetime | None = None geloescht: AwareDatetime | None = None
form_data: dict[str, Any] db_data: dict[str, Any]
class Grunderfassung_Unternehmen(FlatBaseModel): class Grunderfassung_Unternehmen(FlatBaseModel):
+76 -42
View File
@@ -1532,9 +1532,17 @@ class AutoForm(QWidget):
def _delete_data(self) -> None: def _delete_data(self) -> None:
assert self.STATE.rec_id is not None, "deletion initialised despite no index set" assert self.STATE.rec_id is not None, "deletion initialised despite no index set"
self.cfg.data_delete(self.STATE.rec_id) confirm = get_user_confirmation(
self,
"Löschen bestätigen",
"Soll der Eintrag wirklich gelöscht werden?",
)
if not confirm:
return
self.STATE.geloescht = True
self.save_data()
self.update_triggered.emit() self.update_triggered.emit()
self.reset_form()
def _load_from_id( def _load_from_id(
self, self,
@@ -1544,28 +1552,26 @@ class AutoForm(QWidget):
return return
logger_auto_form.info("[Auto-Form] Load data method...") logger_auto_form.info("[Auto-Form] Load data method...")
logger_auto_form.debug("[Auto-Form] Lookup ID: %s", id_)
self.reset_form() self.reset_form()
logger_auto_form.debug("[Auto-Form] Lookup ID: %s", id_) if id_ is None:
if id_ is not None:
logger_auto_form.debug("Load from DB:")
returned = self.cfg.from_db(id_)
# loaded_data = self.cfg.data_get(lookup_id)
# TODO add path to avoid unnecessary loading (where the same ID is loaded
# twice in a row) -- use an internal marker (not state-related)
else:
logger_auto_form.debug("[Auto-Form] Loading: Lookup ID NULL. Do nothing!") logger_auto_form.debug("[Auto-Form] Loading: Lookup ID NULL. Do nothing!")
return return
logger_auto_form.debug("Load from DB:")
returned = self.cfg.from_db(id_)
# TODO add path to avoid unnecessary loading (where the same ID is loaded
# twice in a row) -- use an internal marker (not state-related)
# logger_auto_form.debug( # logger_auto_form.debug(
# "[Auto-Form] Loaded data dict:\n%s Passing to Pydantic...", pformat(loaded_data) # "[Auto-Form] Loaded data dict:\n%s Passing to Pydantic...", pformat(loaded_data)
# ) # )
logger_auto_form.debug( logger_auto_form.debug(
"[Auto-Form] Loaded data dict:\n%s Passing to Pydantic...", "[Auto-Form] Loaded data dict:\n%s Passing to Pydantic...",
pformat(returned.form_data), pformat(returned.db_data),
) )
model = self.cfg.model(**returned.form_data) model = self.cfg.model(**returned.db_data)
logger_auto_form.debug("[Auto-Form] Loaded to Pydantic.") logger_auto_form.debug("[Auto-Form] Loaded to Pydantic.")
logger_auto_form.debug("[Auto-Form] Convert to GUI structure...") logger_auto_form.debug("[Auto-Form] Convert to GUI structure...")
form_data = model.to_gui() form_data = model.to_gui()
@@ -1573,13 +1579,17 @@ class AutoForm(QWidget):
logger_auto_form.debug("[Auto-Form] Form data:\n%s", pformat(form_data)) logger_auto_form.debug("[Auto-Form] Form data:\n%s", pformat(form_data))
self._set_form_data(form_data) self._set_form_data(form_data)
self.STATE.rec_id = id_ self.STATE.rec_id = id_
self._activate_delete() self.STATE.form_data = self._get_form_data()
logger_auto_form.debug(
"####### model dump vs get form data:\n%s\n\n%s",
pformat(model.model_dump(mode="python")),
pformat(self.STATE.form_data),
)
def reset_form(self) -> None: def reset_form(self) -> None:
reset_form(self.widget_registry) reset_form(self.widget_registry)
self.STATE.rec_id = None self.STATE.rec_id = None
self.STATE.form_data = None self.STATE.form_data = None
self._activate_delete()
def lock_form(self) -> None: def lock_form(self) -> None:
self.STATE.locked = True self.STATE.locked = True
@@ -1614,17 +1624,21 @@ class AutoForm(QWidget):
section: Literal["form", "locking"] | None, section: Literal["form", "locking"] | None,
) -> None: ) -> None:
if section is None or section == "form": if section is None or section == "form":
self._load_from_id(self.STATE.rec_id) if not self.STATE.geloescht:
self._load_from_id(self.STATE.rec_id)
else:
self.reset_form()
if section is None or section == "locking": if section is None or section == "locking":
if self.STATE.locked: if self.STATE.locked:
if self.edit_buttons is not None: if self.edit_buttons is not None:
self.edit_buttons.set_modify_state(False) self.edit_buttons.set_modify_state(False, set_delete_btn=True)
lock_form(self.widget_registry) lock_form(self.widget_registry)
else: else:
if self.edit_buttons is not None: if self.edit_buttons is not None:
self.edit_buttons.set_modify_state(True) self.edit_buttons.set_modify_state(True, set_delete_btn=False)
unlock_form(self.widget_registry) unlock_form(self.widget_registry)
self._activate_delete()
def _sync_GUI_to_state(self) -> None: def _sync_GUI_to_state(self) -> None:
form_data = self._get_form_data() form_data = self._get_form_data()
@@ -1647,14 +1661,46 @@ class AutoForm(QWidget):
return self.STATE return self.STATE
def _load_from_pydantic(self, data: Initrec) -> None: def _load_from_pydantic(
self,
data: Initrec,
) -> None:
self.STATE.rec_id = data.rec_id self.STATE.rec_id = data.rec_id
self.STATE.form_data = data.form_data self.STATE.form_data = None
self.STATE.geloescht = True if data.geloescht else False self.STATE.geloescht = True if data.geloescht else False
self._sync_state_to_GUI(None) # TODO change to correct loading self._sync_state_to_GUI(None) # TODO change to correct loading
def save_data(self) -> None: def save_data(self) -> None:
if self.STATE.rec_id is None and self.STATE.geloescht:
logger_auto_form.debug(
"[Auto-Form] This was never saved in the database "
"and is marked for deletion - ignore."
)
return
elif self.STATE.rec_id is not None and self.STATE.geloescht:
logger_auto_form.debug(
"[Auto-Form] This was saved in the database "
"and is marked for deletion - fast path."
)
deleted_datetime = datetime.datetime.now(datetime.UTC)
assert self.STATE.form_data, "cannot delete entry with uninitialised form data"
to_db = Initrec(
rec_id=self.STATE.rec_id,
geloescht=deleted_datetime,
db_data={},
)
returned = self.cfg.to_db(to_db)
self._load_from_pydantic(returned)
msg_box = get_message_box(
QMessageBox.Icon.Information,
"Löschen erfolgreich",
"Der Eintrag wurde erfolgreich gelöscht",
)
msg_box.exec()
return
self._disable_save() self._disable_save()
errors = self.validate() errors = self.validate()
@@ -1699,23 +1745,12 @@ class AutoForm(QWidget):
to_db = Initrec( to_db = Initrec(
rec_id=self.STATE.rec_id, rec_id=self.STATE.rec_id,
geloescht=deleted_datetime, geloescht=deleted_datetime,
form_data=db_data, db_data=db_data,
) )
returned = self.cfg.to_db(to_db) returned = self.cfg.to_db(to_db)
self._load_from_pydantic(returned) self._load_from_pydantic(returned)
# if self.STATE.rec_id is None:
# logger_auto_form.debug("[Auto-Form] Insert triggered...")
# init_rec_id = self.cfg.data_insert(db_data)
# assert isinstance(init_rec_id, int)
# self.STATE.rec_id = init_rec_id
# else:
# logger_auto_form.debug("[Auto-Form] Update triggered...")
# self.cfg.data_update(self.STATE.rec_id, db_data)
self.update_triggered.emit() self.update_triggered.emit()
self._activate_delete()
except Exception as err: except Exception as err:
msg_box = get_message_box( msg_box = get_message_box(
QMessageBox.Icon.Warning, QMessageBox.Icon.Warning,
@@ -2790,6 +2825,11 @@ class MainPage_ClickableCell(ClickableCell):
super().__init__(text=text) super().__init__(text=text)
self.data_record = data_record self.data_record = data_record
logger_gui.debug(
"Initialised ClickableCell on MainPage with data record:\n%s",
pformat(self.data_record),
)
def mousePressEvent(self, event): def mousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton: if event.button() == Qt.MouseButton.LeftButton:
self.clicked.emit(self.data_record) self.clicked.emit(self.data_record)
@@ -2903,10 +2943,6 @@ CONFIG_GRUNDERFASSUNG_UNTERNEHMEN: Final[AutoFormConfig] = AutoFormConfig(
model=Grunderfassung_Unternehmen, model=Grunderfassung_Unternehmen,
to_db=backend.initrec_company_to_db, to_db=backend.initrec_company_to_db,
from_db=backend.initrec_company_from_db, from_db=backend.initrec_company_from_db,
data_insert=backend.initrec_company_insert_initial_recording,
data_update=backend.initrec_company_update_initial_recording,
data_get=backend.initrec_company_get_initial_recording,
data_delete=backend.initrec_company_delete_initial_recording,
ignored_keys=( ignored_keys=(
"Metadaten_erstellung", "Metadaten_erstellung",
"Metadaten_aktualisierung", "Metadaten_aktualisierung",
@@ -2918,10 +2954,6 @@ CONFIG_GRUNDERFASSUNG_PERSONEN: Final[AutoFormConfig] = AutoFormConfig(
model=Grunderfassung_Personen, model=Grunderfassung_Personen,
to_db=backend.initrec_person_to_db, to_db=backend.initrec_person_to_db,
from_db=backend.initrec_person_from_db, from_db=backend.initrec_person_from_db,
data_insert=backend.initrec_person_insert_initial_recording,
data_update=backend.initrec_person_update_initial_recording,
data_get=backend.initrec_person_get_initial_recording,
data_delete=backend.initrec_person_delete_initial_recording,
ignored_keys=( ignored_keys=(
"Metadaten_erstellung", "Metadaten_erstellung",
"Metadaten_aktualisierung", "Metadaten_aktualisierung",
@@ -3100,6 +3132,7 @@ class Page_InitRecCompany(QWidget):
form_data=None, form_data=None,
locked=self.STATE.locked, locked=self.STATE.locked,
) )
logger_gui.debug(">>>>>>>>>>>>> AutoForm State:\n%s", pformat(auto_form_state))
self.auto_form.load_state(auto_form_state) self.auto_form.load_state(auto_form_state)
if section is None or section == "comp_profile": if section is None or section == "comp_profile":
@@ -4490,7 +4523,6 @@ class Page_Consulting(QWidget):
"[Consulting Page] Pydantic model:\n%s", consulting_process "[Consulting Page] Pydantic model:\n%s", consulting_process
) )
# !! should be placed in a try block to handle errors
res = backend.page_consulting_to_db(consulting_process) res = backend.page_consulting_to_db(consulting_process)
if res.status != STATUS_HANDLER.SUCCESS: if res.status != STATUS_HANDLER.SUCCESS:
logger_page_consulting.error( logger_page_consulting.error(
@@ -5294,11 +5326,13 @@ class EditButtons(QWidget):
def set_modify_state( def set_modify_state(
self, self,
enable_modification: bool, enable_modification: bool,
set_delete_btn: bool = True,
) -> None: ) -> None:
if self.modify_button is not None: if self.modify_button is not None:
self.modify_button.set_modify_state(enable_modification) self.modify_button.set_modify_state(enable_modification)
self.save_btn.setEnabled(enable_modification) self.save_btn.setEnabled(enable_modification)
self.delete_btn.setEnabled(enable_modification) if set_delete_btn:
self.delete_btn.setEnabled(enable_modification)
class MainWindow(QMainWindow): class MainWindow(QMainWindow):