generated from dopt-python/py311
refactoring and basic loading of existing consultations on the company profile
This commit is contained in:
+209
-9
@@ -1,9 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import dataclasses as dc
|
||||
import datetime
|
||||
import enum
|
||||
import json
|
||||
from typing import Annotated, Any, Final, Literal
|
||||
from collections.abc import Iterable, Sequence
|
||||
from typing import TYPE_CHECKING, Annotated, Any, Final, Generic, Protocol, TypeVar
|
||||
|
||||
from pydantic import (
|
||||
AwareDatetime,
|
||||
@@ -16,8 +18,16 @@ from pydantic import (
|
||||
)
|
||||
from pydantic_core import ErrorDetails
|
||||
|
||||
ValidAge = Annotated[int, Field(ge=0, le=99)]
|
||||
from wce_crm.form_defs import FormField
|
||||
from wce_crm.types import ConsId, ConsultingType, RecId, UserId
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from wce_crm.gui import Page_Consulting_ConsultingSession # noqa: F401
|
||||
|
||||
ValidAge = Annotated[int, Field(ge=0, le=99)]
|
||||
COLUMN_SEP: Final[str] = "__"
|
||||
M = TypeVar("M", bound="Module")
|
||||
S = TypeVar("S", bound="PageState")
|
||||
|
||||
# // validation translation
|
||||
GERMAN_ERROR_MESSAGES: Final[dict[str, str]] = {
|
||||
@@ -64,9 +74,204 @@ def _parse_json(value: Any) -> str:
|
||||
raise TypeError
|
||||
|
||||
|
||||
COLUMN_SEP: Final[str] = "__"
|
||||
# // GUI states and types
|
||||
def set_page_state(
|
||||
target: S,
|
||||
source: S,
|
||||
deep: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
transfer all field values generically from 'source' to 'target'
|
||||
"""
|
||||
if not (dc.is_dataclass(target) and dc.is_dataclass(source)):
|
||||
raise TypeError("Both source and atrget must be dataclasses")
|
||||
|
||||
if type(target) is not type(source):
|
||||
raise TypeError("Both source and target must have the same type")
|
||||
|
||||
for field in dc.fields(source):
|
||||
if field.name == "child_modules":
|
||||
continue
|
||||
|
||||
new_value = getattr(source, field.name)
|
||||
|
||||
if deep:
|
||||
new_value = copy.deepcopy(new_value)
|
||||
|
||||
setattr(target, field.name, new_value)
|
||||
|
||||
|
||||
class WrapperModule(Protocol):
|
||||
def _sync_state_to_GUI(self) -> None:
|
||||
"""build states for all child modules and use their `load_state` method
|
||||
to initialise them with the new data
|
||||
"""
|
||||
...
|
||||
|
||||
def _sync_GUI_to_state(self) -> None:
|
||||
"""call `get_state` method on all child modules and assign respective
|
||||
properties to state of parent module
|
||||
"""
|
||||
...
|
||||
|
||||
def load_state(self, new_state: Any) -> None: ...
|
||||
|
||||
def get_state(self) -> Any:
|
||||
"""should always be a simple call to `_sync_GUI_to_state` and then returning
|
||||
the module's state
|
||||
|
||||
Returns
|
||||
-------
|
||||
Any
|
||||
state of the respective module
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
class Module(WrapperModule, Protocol):
|
||||
def validate(self) -> list[str]:
|
||||
"""should be a list of field names which could not be validated successfully,
|
||||
propagates through: parent components must call this on all child modules and extend
|
||||
their own error list with the return value
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[str]
|
||||
list of error fields (form field label)
|
||||
"""
|
||||
...
|
||||
|
||||
def save_data(self) -> None: ...
|
||||
|
||||
|
||||
class AutoFormInsert(Protocol):
|
||||
def __call__(
|
||||
self,
|
||||
data: dict[str, Any],
|
||||
) -> RecId: ...
|
||||
|
||||
|
||||
class AutoFormUpdate(Protocol):
|
||||
def __call__(
|
||||
self,
|
||||
id_: int,
|
||||
data: dict[str, Any],
|
||||
) -> None: ...
|
||||
|
||||
|
||||
class AutoFormGet(Protocol):
|
||||
def __call__(
|
||||
self,
|
||||
id_: int,
|
||||
) -> dict[str, Any]: ...
|
||||
|
||||
|
||||
class AutoFormDelete(Protocol):
|
||||
def __call__(
|
||||
self,
|
||||
id_: int,
|
||||
) -> None: ...
|
||||
|
||||
|
||||
@dc.dataclass(slots=True)
|
||||
class Session:
|
||||
user_id: UserId
|
||||
user_name: str
|
||||
|
||||
|
||||
@dc.dataclass(slots=True)
|
||||
class PageState(Generic[M]):
|
||||
child_modules: list[M] = dc.field(default_factory=list)
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class Page_MainPage_State(PageState[Module]):
|
||||
session: Session
|
||||
row_count: int = 0
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class Page_NewInitRec_State(PageState[Module]):
|
||||
session: Session
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class Page_InitRecCompany_State(PageState[Module]):
|
||||
session: Session
|
||||
un_id: RecId | None = None
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=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
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class AutoForm_State(PageState[Module]):
|
||||
session: Session
|
||||
cfg: AutoFormConfig
|
||||
rec_id: RecId | None = None
|
||||
form_data: dict[str, Any] | None = None
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class Page_InitRecPerson_State(PageState[Module]):
|
||||
session: Session
|
||||
pers_id: RecId | None = None
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class Page_Consulting_State(PageState[Module]):
|
||||
session: Session
|
||||
vorgang_id: ConsId | None
|
||||
un_id: RecId | None = None
|
||||
pers_id: RecId | None = None
|
||||
titel: str = "TEST-TITEL" # add title later to GUI or build it in the background
|
||||
beratungs_typ: ConsultingType
|
||||
cons_sessions: list[Page_Consulting_ConsultingSession_State] = dc.field(
|
||||
default_factory=list
|
||||
)
|
||||
ist_geloescht: bool = False
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class Page_Consulting_ConsultingSession_State(PageState[Module]):
|
||||
session: Session
|
||||
nutzer_id: UserId # must be set with the session (always known)
|
||||
nutzer_name: str # must be set with the session (always known)
|
||||
beratung_id: int | None # known and not known entries
|
||||
zeitstempel: datetime.datetime | None = None
|
||||
# dc.field(default_factory=lambda: datetime.datetime.now(tz=datetime.UTC))
|
||||
ansprechpartner: str | None = None
|
||||
kommunikationsweg: str | None = None
|
||||
thema_crm_matrix: str | None = (
|
||||
None # TODO should be linked to something, target unclear (need specification by customer)
|
||||
)
|
||||
anmerkungen: str | None = None
|
||||
rueckmeldung: str | None = None
|
||||
ist_geloescht: bool = False
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class Page_Consulting_Table_State(PageState["Page_Consulting_ConsultingSession"]):
|
||||
session: Session
|
||||
row_states: list[Page_Consulting_ConsultingSession_State] = dc.field(default_factory=list)
|
||||
|
||||
|
||||
@dc.dataclass(slots=True, kw_only=True)
|
||||
class Page_CompanyProfile_State(PageState[Module]):
|
||||
session: Session
|
||||
rec_id: RecId | None = None
|
||||
|
||||
|
||||
# // Pydantic models
|
||||
class FlatBaseModel(BaseModel):
|
||||
"""
|
||||
Optimised Pydantic base class, which parses JSON strings and column
|
||||
@@ -347,11 +552,6 @@ class Grunderfassung_Sprachen(BaseModel):
|
||||
|
||||
|
||||
# ** Consulting
|
||||
class ConsultingType(enum.StrEnum):
|
||||
PAUSCHAL = enum.auto()
|
||||
INDIVIDUAL = enum.auto()
|
||||
|
||||
|
||||
class Beratungsgespraech_Vorgang(BaseModel):
|
||||
model_config = ConfigDict(str_strip_whitespace=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user