diff --git a/src/wce_crm/backend/backend.py b/src/wce_crm/backend/backend.py index 2b0c0b4..d23b884 100644 --- a/src/wce_crm/backend/backend.py +++ b/src/wce_crm/backend/backend.py @@ -24,6 +24,8 @@ from wce_crm.types import ( ConsultingType, ContactPersonInfo, InitRecType, + LinkingConsultationsEntryCompany, + LinkingConsultationsEntryPerson, MainPageEntry, ) @@ -315,71 +317,6 @@ def initrec_person_from_db( ) -# def initrec_person_to_db( -# auto_form_data: Initrec, -# ) -> Initrec_FromDb: -# logger.debug("[AutoForm -- backend] Call database saving routine...") - -# dump_data = copy.deepcopy(auto_form_data.form_data) -# dump_data["geloescht"] = auto_form_data.geloescht - -# return_from_db: Initrec_FromDb - -# with db.ENGINE.begin() as conn: -# if auto_form_data.rec_id is None: -# # insert new "Vorgang" -# logger.debug("[AutoForm -- backend] Insert...") - -# stmt = db.grunderfassung_personen.insert().returning( -# db.grunderfassung_personen.c.pers_id, -# db.grunderfassung_personen.c.Metadaten_aktualisierung, -# db.grunderfassung_personen.c.geloescht, -# ) -# ret = conn.execute(stmt, dump_data) -# if ret.rowcount == 0: -# raise IOError("Entry was not inserted correctly") - -# from_db = ret.mappings().fetchall() -# assert len(from_db) == 1, "expected excactly one returned row" -# data_from_db = from_db[0] -# return_from_db = Initrec_FromDb( -# rec_id=data_from_db["un_id"], -# geloescht=data_from_db["geloescht"], -# Metadaten_aktualisierung=data_from_db["Metadaten_aktualisierung"], -# ) - -# logger.debug("[AutoForm -- backend] Inserted InitRec successfully") - -# else: -# logger.debug("[AutoForm -- backend] Update...") -# stmt = ( -# db.beratung_vorgang.update() -# .where(db.grunderfassung_personen.c.pers_id == auto_form_data.rec_id) -# .returning( -# db.grunderfassung_personen.c.Metadaten_aktualisierung, -# db.grunderfassung_personen.c.geloescht, -# ) -# ) -# ret = conn.execute(stmt, dump_data) - -# from_db = ret.mappings().fetchall() -# assert len(from_db) == 1, "expected excatly one returned row" -# data_from_db = from_db[0] - -# return_from_db = Initrec_FromDb( -# rec_id=auto_form_data.rec_id, -# geloescht=data_from_db["geloescht"], -# Metadaten_aktualisierung=data_from_db["Metadaten_aktualisierung"], -# ) - -# logger.debug( -# "[AutoForm -- backend] Updated InitRec with ID %d successfully", -# auto_form_data.rec_id, -# ) - -# return return_from_db - - def initrec_company_get_initial_recording( id_: RecId, ) -> dict[str, Any]: @@ -580,30 +517,6 @@ def page_consulting_delete( db.beratung_einzelberatung.c.geloescht.is_(None), ) conn.execute(stmt, dump_data) - return - - stmt = db.beratung_einzelberatung.select().where( - db.beratung_einzelberatung.c.vorgang_id == cons_id, - db.beratung_einzelberatung.c.geloescht.is_(None), - ) - ret = conn.execute(stmt) - cons_sessions = ret.mappings().all() - # empty results possible - if not cons_sessions: - logger.debug("[Consulting Page] No sessions, return directly...") - return - - rows_for_db_update: list[dict[str, Any]] = [] - for row_data in cons_sessions: - row_data_dump = copy.deepcopy(dump_data) - row_data_dump["b_beratung_id"] = row_data["beratung_id"] - rows_for_db_update.append(row_data_dump) - - if rows_for_db_update: - stmt = db.beratung_einzelberatung.update().where( - db.beratung_einzelberatung.c.beratung_id == sql.bindparam("b_beratung_id") - ) - conn.execute(stmt, rows_for_db_update) @wrap_result(11) @@ -682,6 +595,105 @@ def page_consulting_from_db( # // consulting page interaction +def page_consulting_linking_companies( + un_id: RecId | None, +) -> list[LinkingConsultationsEntryCompany]: + with db.ENGINE.connect() as conn: + q_relevant_companies = sql.select( + db.grunderfassung_unternehmen.c.un_id, + db.grunderfassung_unternehmen.c.Partnersuche__un_suche, + ).where( + db.grunderfassung_unternehmen.c.geloescht.is_(None), + db.grunderfassung_unternehmen.c.Partnersuche__un_suche.is_not(None), + ) + if un_id is not None: + q_relevant_companies = q_relevant_companies.where( + db.grunderfassung_unternehmen.c.un_id == un_id + ) + + q_relevant_companies = q_relevant_companies.subquery("relevant_companies") + + stmt = sql.select( + q_relevant_companies.c.un_id, + db.ext_crm_master_attach.c.ma_unternehmensname, + ).select_from( + q_relevant_companies.join( + db.ext_crm_master_attach, + q_relevant_companies.c.Partnersuche__un_suche + == db.ext_crm_master_attach.c.ma_id, + ) + ) + + ret = conn.execute(stmt) + company_names = ret.mappings().all() + if not company_names: + raise ValueError(f"No companies found for 'un_id': {un_id}") + + logger.debug("[Page Consulting -- Linking] Retrieved company names:\n%s", company_names) + + linking_entries: list[LinkingConsultationsEntryCompany] = [] + for entry in company_names: + linking_entries.append( + LinkingConsultationsEntryCompany( + un_id=entry["un_id"], + display_name=entry["ma_unternehmensname"], + ) + ) + + return linking_entries + + +def page_consulting_linking_persons( + un_id: RecId | None, +) -> list[LinkingConsultationsEntryPerson]: + with db.ENGINE.connect() as conn: + # if un_id None: list all persons + # else: list just the persons associated with the company + + person_select = sql.select( + db.grunderfassung_personen.c.pers_id, + db.grunderfassung_personen.c.Stammdaten__name, + db.grunderfassung_personen.c.Stammdaten__vorname, + db.grunderfassung_personen.c.Stammdaten__ort, + ) + + if un_id is not None: + person_select = person_select.select_from( + db.grunderfassung_personen.join( + db.zuordnung_personen_unternehmen, + db.grunderfassung_personen.c.pers_id + == db.zuordnung_personen_unternehmen.c.pers_id, + ) + ).where(db.zuordnung_personen_unternehmen.c.un_id == un_id) + + ret = conn.execute(person_select) + person_names = ret.mappings().all() + if not person_names: + logger.warning(f"No persons found for 'un_id': {un_id}") + return [] + + logger.debug("[Page Consulting -- Linking] Retrieved person names:\n%s", person_names) + + linking_entries: list[LinkingConsultationsEntryPerson] = [] + for entry in person_names: + first_name = entry["Stammdaten__vorname"] + last_name = entry["Stammdaten__name"] + location_city = entry["Stammdaten__ort"] + + display_name = f"{first_name} {last_name}" + if location_city: + display_name += f" (Ort: {location_city})" + + linking_entries.append( + LinkingConsultationsEntryPerson( + pers_id=entry["pers_id"], + display_name=display_name, + ) + ) + + return linking_entries + + def companyprofile_page_get_consultations( un_id: RecId, ) -> CompanyProfileConsultations: diff --git a/src/wce_crm/data_models.py b/src/wce_crm/data_models.py index 94d30e0..b444340 100644 --- a/src/wce_crm/data_models.py +++ b/src/wce_crm/data_models.py @@ -266,6 +266,14 @@ class Page_Consulting_State(PageState[Module]): locked: bool +@dc.dataclass(slots=True, kw_only=True) +class Page_Consulting_Linking_State(PageState[Module]): + session: Session + un_id: RecId | None = None + pers_id: RecId | None = None + beratungs_typ: ConsultingType + + @dc.dataclass(slots=True, kw_only=True) class Page_Consulting_ConsultingSession_State(PageState[Module]): session: Session diff --git a/src/wce_crm/db.py b/src/wce_crm/db.py index c990f04..737ed5f 100644 --- a/src/wce_crm/db.py +++ b/src/wce_crm/db.py @@ -7,7 +7,7 @@ from pathlib import Path import polars as pl import sqlalchemy as sql -from sqlalchemy import Column, String, Table, TypeDecorator +from sqlalchemy import Column, String, Table, TypeDecorator, event from wce_crm import constants from wce_crm import types as t @@ -63,6 +63,14 @@ MD_MAIN = sql.MetaData() ENGINE = sql.create_engine(f"sqlite:///{constants.Config.DB_PATH_MAIN}") +@event.listens_for(ENGINE, "connect") +def attach_second_db(dbapi_connection, connection_record): + cursor = dbapi_connection.cursor() + # 'kontaktliste' is the alias for the second DB + cursor.execute(f"ATTACH DATABASE '{constants.Config.DB_PATH_CRM}' AS kontaktliste") + cursor.close() + + ext_crm_master: sql.Table = Table( "Master", MD_CRM, @@ -247,6 +255,37 @@ def get_ext_crm_contact_person( # df_contact_person = get_ext_crm_contact_person(None) DF_CONTACT_PERSON = get_ext_crm_contact_person(constants.Config.DB_PATH_CRM) +ext_crm_master_attach: sql.Table = Table( + "Master", + MD_CRM, + Column("ma_id", sql.Integer, nullable=False, unique=True), + Column("wce_id", sql.ForeignKey("Nutzer.wce_id")), + Column("ma_unternehmensname", sql.Text, nullable=True), + Column("ma_branche", sql.Text, nullable=True), + Column("ma_strasse", sql.Text, nullable=True), + Column("ma_hausnummer", sql.Text, nullable=True), + Column("ma_plz", sql.Text, nullable=True), + Column("ma_ort", sql.Text, nullable=True), + Column("ma_plz_postfach", sql.Text, nullable=True), + Column("ma_postfach", sql.Text, nullable=True), + Column("ma_website", sql.Text, nullable=True), + Column("ma_mail", sql.Text, nullable=True), + Column("ma_telefonnummer", sql.Text, nullable=True), + Column("ma_faxnummer", sql.Text, nullable=True), + Column("ma_ersteintrag_datum", SafeDateTime, nullable=True), + Column("ma_aktualisierung_datum", SafeDateTime, nullable=True), + Column("ma_aktualisierung_nutzer", sql.Text, nullable=True), + Column("ma_sollprozess", sql.Text, nullable=True), + Column("ma_auslaendische_mitarbeiter", sql.Text, nullable=True), + Column("ma_quelle_information", sql.Text, nullable=True), + Column("ma_bemerkung", sql.Text, nullable=True), + Column("ma_kontakt", sql.Boolean, nullable=True), + Column("ma_schlagworte", sql.Text, nullable=True), + Column("ma_archiviert", sql.Boolean, nullable=True, default=False), + schema="kontaktliste", +) + + grunderfassung_unternehmen: sql.Table = Table( "grunderfassung_unternehmen", MD_MAIN, diff --git a/src/wce_crm/gui.py b/src/wce_crm/gui.py index 08b2b60..f0fa05e 100644 --- a/src/wce_crm/gui.py +++ b/src/wce_crm/gui.py @@ -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("Unternehmen wählen (Optional):")) + 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("Person wählen (Optional):")) + 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' diff --git a/src/wce_crm/types.py b/src/wce_crm/types.py index a4c0715..9f9f943 100644 --- a/src/wce_crm/types.py +++ b/src/wce_crm/types.py @@ -103,3 +103,15 @@ class CompanyProfileConsultationEntry: class CompanyProfileConsultations: pauschal: list[CompanyProfileConsultationEntry] individual: list[CompanyProfileConsultationEntry] + + +@dc.dataclass(slots=True) +class LinkingConsultationsEntryCompany: + un_id: RecId + display_name: str + + +@dc.dataclass(slots=True) +class LinkingConsultationsEntryPerson: + pers_id: RecId + display_name: str