diff --git a/src/wce_crm/gui.py b/src/wce_crm/gui.py index d3eeb85..86b2e9e 100644 --- a/src/wce_crm/gui.py +++ b/src/wce_crm/gui.py @@ -3,6 +3,7 @@ from __future__ import annotations import copy import dataclasses as dc import datetime +import enum import pickle import re import sys @@ -2392,12 +2393,25 @@ class Page_InitRecPerson(QWidget): self.auto_form.reset_form() +class ConsultingType(enum.StrEnum): + PAUSCHAL = enum.auto() + INDIVIUAL = enum.auto() + + +@dc.dataclass(slots=True, kw_only=True) +class ConsultingRequest: + cons_type: ConsultingType + un_id: InitRecId | None = None + pers_id: InitRecId | None = None + + class Page_CompanyProfile(QWidget): back_main_requested = Signal() # back to main page back_requested = Signal(bool) # back to init rec (bool: reset yes/no) # TODO update should trigger something else # more like listening to 'child' ("Beratungen") # update_triggered = Signal() # form saved (data changed for front page) + consulting_requested = Signal(ConsultingRequest) def __init__(self): super().__init__() @@ -2541,6 +2555,9 @@ class Page_CompanyProfile(QWidget): ) top_right_layout.addWidget(common_consultancy_label) top_right_new_btn = QPushButton("+ Hinzufügen") + top_right_new_btn.clicked.connect( + lambda: self._request_consulting(ConsultingType.PAUSCHAL) + ) top_right_new_btn.setSizePolicy( QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed ) @@ -2560,6 +2577,9 @@ class Page_CompanyProfile(QWidget): ) bottom_right_layout.addWidget(individual_consultancy_label) bottom_right_new_btn = QPushButton("+ Hinzufügen") + bottom_right_new_btn.clicked.connect( + lambda: self._request_consulting(ConsultingType.INDIVIUAL) + ) bottom_right_new_btn.setSizePolicy( QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed ) @@ -2605,6 +2625,16 @@ class Page_CompanyProfile(QWidget): # } # """) + def _request_consulting( + self, + cons_type: ConsultingType, + ) -> None: + assert self.current_id > -1, ( + "tried to call consulting from comp profile without set ID" + ) + req = ConsultingRequest(cons_type=cons_type, un_id=self.current_id) + self.consulting_requested.emit(req) + def set_company_name(self, name: str) -> None: if not name: name = self.change_title_text.text() @@ -2619,6 +2649,7 @@ class Page_CompanyProfile(QWidget): id_: InitRecId, ) -> None: assert id_ is not None, "tried to load with InitRecId None" + assert id_, "tried to load with invalid InitRecId" logger_gui.debug(f"Called function to load with ID: {id_}") if id_ < 0: @@ -2827,6 +2858,271 @@ class MasterDataFormWidget(QWidget): """) +class Page_Consulting(QWidget): + back_main_requested = Signal() # back to main page + back_requested = Signal(bool) # back to init rec (bool: reset yes/no) + # TODO update should trigger something else + # more like listening to 'child' ("Beratungen") + # 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() + # main_layout.setContentsMargins(0, 0, 0, 0) + outer_layout.addStretch(1) + outer_layout.addLayout(vert_layout, stretch=100) + outer_layout.addStretch(1) + # Optional: Damit der Container oben am Rand klebt + outer_layout.setAlignment(Qt.AlignmentFlag.AlignTop) + + # --- HEADER --- + header_container = QWidget() + header_container.setMinimumWidth(700) + header_container.setMaximumWidth(1200) + header_container.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + header_layout = QVBoxLayout(header_container) + header_layout.setContentsMargins(0, 0, 0, 10) + + back_btn_main = QPushButton("← Zurück zur Übersicht") + back_btn_main.clicked.connect(lambda: self.back_main_requested.emit()) + back_btn_main.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) + 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(False)) + back_btn_step.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) + back_btn_step.setMinimumWidth(200) + back_btn_step.setMaximumWidth(200) + + title = QLabel("Beratungsgespräch") + title.setStyleSheet("font-size: 20px; font-weight: bold;") + + header_layout.setSpacing(5) + + header_layout.addSpacing(15) + header_layout.addWidget(back_btn_step) + header_layout.addWidget(back_btn_main) + header_layout.addWidget(title) + vert_layout.addWidget(header_container) + + # --- MAIN CONTENT --- + container = QWidget() + # SCROLL AREA + scroll_area = QScrollArea() + scroll_area.setWidgetResizable(True) + scroll_area.setMinimumWidth(700) + scroll_area.setMaximumWidth(1200) + scroll_area.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + # optional: remove frame to look more modern + scroll_area.setFrameShape(QFrame.Shape.NoFrame) + scroll_area.setWidget(container) + + vert_layout.addWidget(scroll_area) + + container_layout = QVBoxLayout(container) + container_layout.setContentsMargins(0, 0, 0, 0) + + # --- MAIN LAYOUT --- + if DEBUG: + separator1 = QFrame() + separator1.setFrameShape(QFrame.Shape.HLine) + separator1.setFrameShadow(QFrame.Shadow.Sunken) + container_layout.addWidget(separator1) + + # layout_change_title = QHBoxLayout() + # self.change_title_text = QLineEdit(placeholderText="Unternehmensname eingeben...") + # layout_change_title.addWidget(self.change_title_text) + # change_title_btn = QPushButton("ändern") + # layout_change_title.addWidget(change_title_btn) + # change_title_btn.clicked.connect(self.set_company_name) + # container_layout.addLayout(layout_change_title) + + separator2 = QFrame() + separator2.setFrameShape(QFrame.Shape.HLine) + separator2.setFrameShadow(QFrame.Shadow.Sunken) + container_layout.addWidget(separator2) + + container_layout.addSpacing(30) + + # self.title_company_name = HeaderCell("Unternehmen: n.v.", font_size=16) + # container_layout.addWidget(self.title_company_name) + container_layout.addWidget(QLabel("PLATZHALTER")) + + container_layout.addSpacing(20) + + # separation in left and right + # main_hor_layout = QHBoxLayout() + # main_hor_layout.setSpacing(20) + # # main_hor_layout.setContentsMargins(20, 20, 20, 20) + + # # left column + # left_frame = QFrame() + # left_frame.setObjectName("Segment") + # left_frame.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Maximum) + # left_layout = QVBoxLayout(left_frame) + # main_hor_layout.addWidget(left_frame, stretch=1, alignment=Qt.AlignmentFlag.AlignTop) + # master_data_label = HeaderCell("Stammdaten & Vermerke") + # master_data_label.setSizePolicy( + # QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed + # ) + # left_layout.addWidget(master_data_label) + # # self.table_master_data = MasterDataTable() + # 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?")) + + # # right column + # right_column_layout = QVBoxLayout() + # right_column_layout.setSpacing(20) + # main_hor_layout.addLayout(right_column_layout, stretch=1) + + # # top right area + # top_right_frame = QFrame() + # top_right_frame.setObjectName("Segment") + # top_right_frame.setSizePolicy( + # QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Maximum + # ) + # top_right_layout = QVBoxLayout(top_right_frame) + # common_consultancy_label = HeaderCell("Pauschalberatung") + # common_consultancy_label.setSizePolicy( + # QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed + # ) + # top_right_layout.addWidget(common_consultancy_label) + # top_right_new_btn = QPushButton("+ Hinzufügen") + # top_right_new_btn.setSizePolicy( + # QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed + # ) + # top_right_new_btn.setMinimumHeight(30) + # top_right_layout.addWidget(top_right_new_btn) + + # # bottom right area + # bottom_right_frame = QFrame() + # bottom_right_frame.setObjectName("Segment") + # bottom_right_frame.setSizePolicy( + # QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Maximum + # ) + # bottom_right_layout = QVBoxLayout(bottom_right_frame) + # individual_consultancy_label = HeaderCell("Individualberatung") + # individual_consultancy_label.setSizePolicy( + # QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed + # ) + # bottom_right_layout.addWidget(individual_consultancy_label) + # bottom_right_new_btn = QPushButton("+ Hinzufügen") + # bottom_right_new_btn.setSizePolicy( + # QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed + # ) + # bottom_right_new_btn.setMinimumHeight(30) + # bottom_right_layout.addWidget(bottom_right_new_btn) + + # right_column_layout.addWidget(top_right_frame) + # right_column_layout.addWidget(bottom_right_frame) + # right_column_layout.addStretch(1) + + # container_layout.addLayout(main_hor_layout) + container_layout.addStretch() + + # --- STYLE --- + self.setStyleSheet(""" + QFrame#Segment { + background-color: #ffffff; + border: 1px solid #e2e8f0; + border-radius: 12px; + padding: 3px; + } + """) + + # self.setStyleSheet(""" + # /* Hintergrund des Hauptfensters */ + # QWidget { + # background-color: #f1f5f9; + # } + + # /* Styling für unsere 3 Segmente */ + # QFrame#Segment { + # background-color: #ffffff; + # border: 1px solid #e2e8f0; + # border-radius: 12px; + # padding: 15px; + # } + + # /* Text-Styling */ + # QLabel { + # color: #334155; + # font-size: 16px; + # font-weight: bold; + # } + # """) + + def load_from_request( + self, + req: ConsultingRequest, + ) -> None: + # TODO add correct loading behaviour + logger_gui.debug("[Consulting] Loading with request:\n%s", req) + + # def set_company_name(self, name: str) -> None: + # if not name: + # name = self.change_title_text.text() + # if not name: + # name = "n.v." + + # 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 + + # init_rec = backend.initrec_company_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_ + + def clear_layout( layout: QLayout | None, ) -> None: @@ -2850,6 +3146,10 @@ def clear_layout( class MainWindow(QMainWindow): def __init__(self): super().__init__() + + # STATE MANAGEMENT + self._history_stack: list[int] = [] + self.setWindowTitle("Master") self.resize(1800, 1000) @@ -2887,7 +3187,16 @@ class MainWindow(QMainWindow): self.company_profile = Page_CompanyProfile() self.company_profile.back_main_requested.connect(self.show_main_page) self.company_profile.back_requested.connect(self.show_page_initrec_company) + self.company_profile.consulting_requested.connect(self.show_page_consulting) self.stack.addWidget(self.company_profile) + # SITE: 'Beratungsgespräch' + self.consulting_page = Page_Consulting() + self.consulting_page.back_main_requested.connect(self.show_main_page) + # self.consulting_page.back_requested.connect( + # self.show_page_company_profile_without_load + # ) + self.consulting_page.back_requested.connect(self.simple_go_back) + self.stack.addWidget(self.consulting_page) def setup_main_page(self): # QMainWindow defines frame --> container widget needed for the middle @@ -3038,28 +3347,53 @@ class MainWindow(QMainWindow): # 2. Auf die Detail-Seite umblättern # self.stack.setCurrentWidget(self.detail_page) + def _navigate_to_target( + self, + widget: QWidget, + ) -> None: + curr_idx = self.stack.currentIndex() + + if curr_idx != -1: + self._history_stack.append(curr_idx) + + self.stack.setCurrentWidget(widget) + + def simple_go_back(self) -> None: + if not self._history_stack: + logger_gui.info("[main program] Called >back< on empty history") + + prev_idx = self._history_stack.pop() + self.stack.setCurrentIndex(prev_idx) + def show_main_page(self): - # Zurück zur Tabelle blättern - self.stack.setCurrentWidget(self.main_page) + self._navigate_to_target(self.main_page) def show_new_entry_select(self): - self.stack.setCurrentWidget(self.new_entry_select) + self._navigate_to_target(self.new_entry_select) def show_page_initrec_company(self, reset: bool): if reset: self.initrec_company.reset_form() - self.stack.setCurrentWidget(self.initrec_company) + self._navigate_to_target(self.initrec_company) def show_page_initrec_person(self): + # TODO: similar to company with reset? self.initrec_person.reset_form() - self.stack.setCurrentWidget(self.initrec_person) + self._navigate_to_target(self.initrec_person) def show_page_company_profile( self, id_: InitRecId, ) -> None: self.company_profile.load_from_id(id_) - self.stack.setCurrentWidget(self.company_profile) + self._navigate_to_target(self.company_profile) + + def show_page_consulting( + self, + req: ConsultingRequest, + ) -> None: + self.consulting_page.load_from_request(req) + self._navigate_to_target(self.consulting_page) # --- MENÜ LOGIK --- def create_menu(self):