prepare dialog for linking open consulting processes

This commit is contained in:
2026-07-21 16:08:32 +02:00
parent 482ae436eb
commit 7bfbdc731b
5 changed files with 493 additions and 92 deletions
+332 -2
View File
@@ -51,6 +51,8 @@ from PySide6.QtWidgets import (
QComboBox,
QCompleter,
QDateEdit,
QDialog,
QDialogButtonBox,
QFormLayout,
QFrame,
QGridLayout,
@@ -60,6 +62,8 @@ from PySide6.QtWidgets import (
QLabel,
QLayout,
QLineEdit,
QListWidget,
QListWidgetItem,
QMainWindow,
QMessageBox,
QPlainTextEdit,
@@ -89,6 +93,7 @@ from wce_crm.data_models import (
Initrec,
Page_CompanyProfile_State,
Page_Consulting_ConsultingSession_State,
Page_Consulting_Linking_State,
Page_Consulting_State,
Page_Consulting_Table_State,
Page_InitRecCompany_State,
@@ -115,8 +120,17 @@ from wce_crm.logging import (
from wce_crm.types import CompanyProfileConsultationEntry, ConsultingType, RecId
if TYPE_CHECKING:
from wce_crm.data_models import AutoForm_State, Module, WrapperModule
from wce_crm.types import ConsId, ExtMaId
from wce_crm.data_models import (
AutoForm_State,
Module,
WrapperModule,
)
from wce_crm.types import (
ConsId,
ExtMaId,
LinkingConsultationsEntryCompany,
LinkingConsultationsEntryPerson,
)
K = TypeVar("K")
V = TypeVar("V")
@@ -2973,6 +2987,7 @@ class Page_InitRecCompany(QWidget):
back_requested = Signal() # back button
update_main_page = Signal() # form saved (data changed for front page)
company_profile_requested = Signal(Page_CompanyProfile_State)
initrec_person_requested = Signal(Page_InitRecPerson_State) # TODO add corresponding call
def __init__(
self,
@@ -3021,12 +3036,20 @@ class Page_InitRecCompany(QWidget):
)
self.comp_profile_btn.setFixedHeight(50)
self.initrec_person_btn = QPushButton("Individualperson erfassen")
self.initrec_person_btn.clicked.connect(self._request_inirec_person)
self.initrec_person_btn.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed
)
self.initrec_person_btn.setFixedHeight(50)
header_layout.setSpacing(5)
header_layout.addWidget(back_btn_step)
header_layout.addWidget(back_btn_main)
header_layout.addWidget(title)
header_layout.addSpacing(15)
header_layout.addWidget(self.comp_profile_btn)
header_layout.addWidget(self.initrec_person_btn)
vert_layout.addWidget(header_container)
# --- BANNER ---
@@ -3119,6 +3142,18 @@ class Page_InitRecCompany(QWidget):
logger_gui.debug("[Page -- InitRec Company] State to call: %s", req_state)
self.company_profile_requested.emit(req_state)
def _request_inirec_person(self) -> None:
assert self.STATE.un_id is not None, (
"requested initrec of person for a company which is not known (no ID)"
)
req_state = Page_InitRecPerson_State(
session=self.STATE.session,
pers_id=None,
locked=False,
)
logger_gui.debug("[Page -- InitRec Company] State to call: %s", req_state)
self.initrec_person_requested.emit(req_state)
def reset(self) -> None:
self.auto_form.reset_form()
@@ -4088,6 +4123,13 @@ class Page_Consulting(QWidget):
db_index_layout.addWidget(db_index_set_button)
container_layout.addLayout(db_index_layout)
linking_button = QPushButton("Verlinkungsdialog öffnen")
linking_button.setSizePolicy(
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred
)
linking_button.clicked.connect(self._open_linking_dialogue)
container_layout.addWidget(linking_button)
separator2 = QFrame()
separator2.setFrameShape(QFrame.Shape.HLine)
separator2.setFrameShadow(QFrame.Shadow.Sunken)
@@ -4264,6 +4306,34 @@ class Page_Consulting(QWidget):
def _open_linking_dialogue(self) -> None:
logger_page_consulting.info("[Consulting Page] Linking dialogue triggered")
# Dialog erstellen und anzeigen
dialog_state = Page_Consulting_Linking_State(
session=self.STATE.session,
un_id=self.STATE.un_id,
pers_id=self.STATE.pers_id,
beratungs_typ=self.STATE.beratungs_typ,
)
dialog = Page_Consulting_LinkingDialog(dialog_state, parent=self)
# .exec() öffnet das Fenster modal (blockiert das Hauptfenster)
if dialog.exec() == QDialog.DialogCode.Accepted:
# Hier hast du am Ende beide (oder nur eine) Entitäten auswertbar vorliegen:
firma = dialog.gewaehltes_unternehmen
person = dialog.gewaehlte_person
comp_name = firma["name"] if firma else "Keine"
person_name = person["name"] if person else "Keine"
logger_page_consulting.info(
"[Consulting Page] Firme gewählt: %s, Person gewählt: %s",
comp_name,
person_name,
)
# 1. TODO: Datenbank-Update ausführen (Fremdschlüssel setzen)
# 2. Banner ausblenden: self.banner.hide()
else:
logger_page_consulting.info("[Consulting Page] Verknüpfung abgebrochen.")
def _clear_info_banners(self) -> None:
while self.info_banners:
banner = self.info_banners[0]
@@ -4663,6 +4733,265 @@ class Page_Consulting(QWidget):
self._sync_state_to_GUI("locking")
class Page_Consulting_LinkingDialog(QDialog):
def __init__(
self,
state: Page_Consulting_Linking_State,
parent: QWidget | None = None,
):
super().__init__(parent)
self.STATE = state
self.setWindowTitle("Beziehung verknüpfen")
self.resize(700, 450)
# firmen_aus_db = [{"id": 1, "name": "Siemens AG"}, {"id": 2, "name": "Bosch GmbH"}]
# personen_aus_db = [
# {
# "id": 50,
# "name": "Max Mustermann",
# "unternehmen_id": 1,
# "firma_name": "Siemens AG",
# },
# {
# "id": 51,
# "name": "Erika Muster",
# "unternehmen_id": 1,
# "firma_name": "Siemens AG",
# },
# {
# "id": 52,
# "name": "Peter Müller",
# "unternehmen_id": 2,
# "firma_name": "Bosch GmbH",
# },
# {
# "id": 53,
# "name": "Freiberufler Frank",
# "unternehmen_id": None,
# "firma_name": None,
# },
# ]
# self.all_unternehmen = firmen_aus_db
# self.all_personen = personen_aus_db
# # Rückgabewerte
# self.gewaehltes_unternehmen = None
# self.gewaehlte_person = None
# --- UI LAYOUT ---
main_layout = QVBoxLayout(self)
column_layout = QHBoxLayout()
# left column: companies
self.vbox_companies = QVBoxLayout()
self.vbox_companies.addWidget(QLabel("<b>Unternehmen wählen (Optional):</b>"))
self.btn_clear_company = QPushButton("Auswahl aufheben")
self.list_companies = QListWidget()
self.vbox_companies.addWidget(self.list_companies)
self.vbox_companies.addWidget(self.btn_clear_company)
# right column: persons
self.vbox_persons = QVBoxLayout()
self.vbox_persons.addWidget(QLabel("<b>Person wählen (Optional):</b>"))
self.btn_clear_person = QPushButton("Auswahl aufheben")
self.list_persons = QListWidget()
self.vbox_persons.addWidget(self.list_persons)
self.vbox_persons.addWidget(self.btn_clear_person)
column_layout.addLayout(self.vbox_companies)
column_layout.addLayout(self.vbox_persons)
main_layout.addLayout(column_layout)
# Unten: OK / Abbrechen Buttons
self.button_box = QDialogButtonBox(
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
)
self.ok_btn = self.button_box.button(QDialogButtonBox.StandardButton.Ok)
self.ok_btn.setText("Verknüpfung speichern")
self.ok_btn.setEnabled(False)
self.button_box.button(QDialogButtonBox.StandardButton.Cancel).setText("Abbrechen")
main_layout.addWidget(self.button_box)
# initial loading
# self._load_companies()
# self._load_persons()
# list_style = """
# QListWidget::item:selected {
# background-color: #0078D4; /* Blau, wenn die Liste aktiv fokussiert ist */
# color: white;
# }
# QListWidget::item:selected:!active {
# background-color: #CCE4F7; /* Gut sichtbares Hellblau, wenn die Liste den Fokus verliert */
# color: black;
# }
# QListWidget::item:hover {
# background-color: #F0F0F0; /* Dezentes Grau beim Drüberfahren */
# }
# """
# self.list_companies.setStyleSheet(list_style)
# self.list_persons.setStyleSheet(list_style)
# signals
self.list_companies.itemSelectionChanged.connect(self._company_selected)
self.list_persons.itemSelectionChanged.connect(self._person_selected)
self.btn_clear_company.clicked.connect(self._clear_company_selection)
self.btn_clear_person.clicked.connect(self._clear_person_selection)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
self._sync_state_to_GUI(reset=True)
def _enable_person_selection(
self,
enable: bool,
) -> None:
logger_page_consulting.debug(">>>>>>> CALL ENABLE: %s", enable)
for i in range(self.vbox_persons.count()):
item = self.vbox_persons.itemAt(i)
if not item:
continue
widget = item.widget()
logger_page_consulting.debug(">>>>>>> Type widget: %s", type(widget))
if isinstance(widget, QWidget):
logger_page_consulting.debug(">>>>>>> Widget (enable=%s): %s", enable, widget)
widget.setEnabled(enable)
def _reset(self) -> None:
self._clear_company_selection()
self._clear_person_selection()
def _sync_state_to_GUI(
self,
reset: bool,
section: Literal["person_selection", "validation"] | None = None,
) -> None:
if reset:
self._reset()
self._load_companies()
if section is None or section == "person_selection":
if self.STATE.beratungs_typ is ConsultingType.PAUSCHAL:
self._enable_person_selection(False)
elif self.STATE.beratungs_typ is ConsultingType.INDIVIDUAL:
self._enable_person_selection(True)
self.list_persons.blockSignals(True)
self._load_persons(self.STATE.un_id)
self.list_persons.blockSignals(False)
if section is None or section == "validation":
self._validate()
def _validate(self) -> None:
valid: bool = False
if self.STATE.beratungs_typ is ConsultingType.PAUSCHAL:
assert self.STATE.pers_id is None
if self.STATE.un_id is not None:
valid = True
elif self.STATE.beratungs_typ is ConsultingType.INDIVIDUAL:
if self.STATE.pers_id is not None:
valid = True
else:
RuntimeError("Undefined consulting type")
if valid:
self.ok_btn.setEnabled(True)
else:
self.ok_btn.setEnabled(False)
def _load_companies(self) -> None:
self.list_companies.clear()
companies = backend.page_consulting_linking_companies(un_id=self.STATE.un_id)
logger_page_consulting.debug(
"[Page Consulting -- Linking] Retrieved company entries:\n%s", companies
)
for company in companies:
item = QListWidgetItem(company.display_name)
item.setData(Qt.ItemDataRole.UserRole, company)
self.list_companies.addItem(item)
def _load_persons(
self,
un_id: RecId | None,
) -> None:
"""Lädt Personen. Wenn firma_id übergeben wird, wird gefiltert."""
self.list_persons.clear()
persons = backend.page_consulting_linking_persons(un_id)
logger_page_consulting.debug(
"[Page Consulting -- Linking] Retrieved person entries:\n%s", persons
)
for person in persons:
item = QListWidgetItem(person.display_name)
item.setData(Qt.ItemDataRole.UserRole, person)
self.list_persons.addItem(item)
# --- LOGIK ---
def _company_selected(self) -> None:
items = self.list_companies.selectedItems()
if not items:
return
company = cast(
"LinkingConsultationsEntryCompany", items[0].data(Qt.ItemDataRole.UserRole)
)
self.STATE.un_id = company.un_id
logger_page_consulting.debug(
"[Page Consulting -- Linking] Company selected. State is:\n%s",
pformat(self.STATE),
)
self._sync_state_to_GUI(reset=False)
# if self.STATE.beratungs_typ is ConsultingType.INDIVIDUAL:
# self.list_persons.blockSignals(True)
# self._load_persons(un_id=self.STATE.un_id)
# self.list_persons.blockSignals(False)
def _person_selected(self) -> None:
items = self.list_persons.selectedItems()
if not items:
return
person = cast(
"LinkingConsultationsEntryPerson", items[0].data(Qt.ItemDataRole.UserRole)
)
self.STATE.pers_id = person.pers_id
self._sync_state_to_GUI(reset=False, section="validation")
# TODO this backlink is a really good idea and should be implemented
# if person["unternehmen_id"]:
# self.list_companies.blockSignals(True)
#
# for i in range(self.list_companies.count()):
# item = self.list_companies.item(i)
# firma_data = item.data(Qt.ItemDataRole.UserRole)
# if firma_data["id"] == person["unternehmen_id"]:
# item.setSelected(True)
# self.gewaehltes_unternehmen = firma_data
# break
# self.list_companies.blockSignals(False)
def _clear_company_selection(self) -> None:
self.list_companies.clearSelection()
self.STATE.un_id = None
self._sync_state_to_GUI(reset=False)
def _clear_person_selection(self) -> None:
self.list_persons.clearSelection()
self.STATE.pers_id = None
self._sync_state_to_GUI(reset=False)
def get_state(self) -> Page_Consulting_Linking_State:
return self.STATE
class Page_Consulting_ConsultingSession(QWidget):
"""child of 'Page_Consulting_DynamicTable'"""
@@ -5461,6 +5790,7 @@ class MainWindow(QMainWindow):
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.update_main_page.connect(self.update_grid)
self.initrec_company.initrec_person_requested.connect(self.show_page_initrec_person)
self.initrec_company.company_profile_requested.connect(self.show_page_company_profile)
self.stack.addWidget(self.initrec_company)
# SITE: 'Grunderfassung Person'