From a515f3b820bf09601b5071e0b3a073e80f9d05eb Mon Sep 17 00:00:00 2001 From: foefl Date: Tue, 28 Jul 2026 08:27:45 +0200 Subject: [PATCH] adapt customer requirements, REQ 1006, 1007 --- ...fc1dfdf_update_schema_to_meet_customer_.py | 48 +++++ data_model/project_db_schema.aml | 3 +- src/wce_crm/backend/backend.py | 6 +- src/wce_crm/data_models.py | 3 +- src/wce_crm/db.py | 31 +--- src/wce_crm/form_defs.py | 166 ++++-------------- src/wce_crm/gui.py | 19 +- 7 files changed, 100 insertions(+), 176 deletions(-) create mode 100644 alembic/versions/5dfa1fc1dfdf_update_schema_to_meet_customer_.py diff --git a/alembic/versions/5dfa1fc1dfdf_update_schema_to_meet_customer_.py b/alembic/versions/5dfa1fc1dfdf_update_schema_to_meet_customer_.py new file mode 100644 index 0000000..24e62ec --- /dev/null +++ b/alembic/versions/5dfa1fc1dfdf_update_schema_to_meet_customer_.py @@ -0,0 +1,48 @@ +"""update schema to meet customer requirements + +Revision ID: 5dfa1fc1dfdf +Revises: e290fe18132d +Create Date: 2026-07-28 08:39:44.168872 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "5dfa1fc1dfdf" +down_revision: Union[str, Sequence[str], None] = "e290fe18132d" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("Grunderfassung_Personen", schema=None) as batch_op: + batch_op.add_column( + sa.Column("Stammdaten__kanal_aufmerksamkeit", sa.Text(), nullable=True) + ) + + with op.batch_alter_table("Personen_Unternehmen_Zuordnung", schema=None) as batch_op: + batch_op.add_column(sa.Column("Partnersuche__kontaktweg", sa.Text(), nullable=True)) + batch_op.drop_column("Partnersuche__kanal_aufmerksamkeit") + + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("Personen_Unternehmen_Zuordnung", schema=None) as batch_op: + batch_op.add_column( + sa.Column("Partnersuche__kanal_aufmerksamkeit", sa.TEXT(), nullable=True) + ) + batch_op.drop_column("Partnersuche__kontaktweg") + + with op.batch_alter_table("Grunderfassung_Personen", schema=None) as batch_op: + batch_op.drop_column("Stammdaten__kanal_aufmerksamkeit") + + # ### end Alembic commands ### diff --git a/data_model/project_db_schema.aml b/data_model/project_db_schema.aml index 12c8bfc..7b10d53 100644 --- a/data_model/project_db_schema.aml +++ b/data_model/project_db_schema.aml @@ -15,7 +15,7 @@ Personen_Unternehmen_Zuordnung pers_id int pk -> Grunderfassung_Personen(pers_id) unique=uq_aktive_zuordnung un_id int -> Unternehmen(un_id) unique=uq_aktive_zuordnung | alias 'Partnersuche__un_suche' an_id int -> Ext_Kontaktliste.Ansprechpartner(an_id) | alias 'Partnersuche__person_suche - Partnersuche__kanal_aufmerksamkeit text nullable + Partnersuche__kontaktweg text nullable erstellt "timestamp with time zone"=`datetime.datetime.now(datetime.UTC)` aktualisiert "timestamp with time zone"=`datetime.datetime.now(datetime.UTC)` {on_update: `datetime.datetime.now(datetime.UTC)`} geloescht "timestamp with time zone" nullable | Soft-Delete Marker (partieller Unique-Index: WHERE geloescht IS NULL) @@ -45,6 +45,7 @@ Grunderfassung_Personen Projektrelevanz__relevanz text nullable Projektrelevanz__foerderperiode text nullable Schulbildung text nullable + Stammdaten__kanal_aufmerksamkeit text nullable Stammdaten__PLZ text nullable Stammdaten__anrede_anschrift text nullable Stammdaten__anzahl_kinder__alter text nullable diff --git a/src/wce_crm/backend/backend.py b/src/wce_crm/backend/backend.py index 6781ce7..228e51e 100644 --- a/src/wce_crm/backend/backend.py +++ b/src/wce_crm/backend/backend.py @@ -506,7 +506,7 @@ def page_initrec_to_db( index_where=sa.text("geloescht IS NULL"), set_={ "an_id": stmt.excluded.an_id, - "Partnersuche__kanal_aufmerksamkeit": stmt.excluded.Partnersuche__kanal_aufmerksamkeit, + "Partnersuche__kontaktweg": stmt.excluded.Partnersuche__kontaktweg, "aktualisiert": datetime.datetime.now(datetime.UTC), "geloescht": data.geloescht, }, @@ -541,7 +541,7 @@ def page_initrec_from_db( db.t_zuordnung_personen_unternehmen.c.pers_id, db.t_zuordnung_personen_unternehmen.c.un_id, db.t_zuordnung_personen_unternehmen.c.an_id, - db.t_zuordnung_personen_unternehmen.c.Partnersuche__kanal_aufmerksamkeit, + db.t_zuordnung_personen_unternehmen.c.Partnersuche__kontaktweg, ).where( db.t_zuordnung_personen_unternehmen.c.id == ids.link_id, ) @@ -552,7 +552,7 @@ def page_initrec_from_db( db.t_zuordnung_personen_unternehmen.c.pers_id, db.t_zuordnung_personen_unternehmen.c.un_id, db.t_zuordnung_personen_unternehmen.c.an_id, - db.t_zuordnung_personen_unternehmen.c.Partnersuche__kanal_aufmerksamkeit, + db.t_zuordnung_personen_unternehmen.c.Partnersuche__kontaktweg, ).where( db.t_zuordnung_personen_unternehmen.c.pers_id == ids.pers_id, db.t_zuordnung_personen_unternehmen.c.un_id == ids.un_id, diff --git a/src/wce_crm/data_models.py b/src/wce_crm/data_models.py index fb6b97f..922c425 100644 --- a/src/wce_crm/data_models.py +++ b/src/wce_crm/data_models.py @@ -564,7 +564,7 @@ class Grunderfassung_PartnerSuche(BaseModel): un_suche: int | None person_suche: int | None - kanal_aufmerksamkeit: str | None + kontaktweg: str | None class Grunderfassung_Projektrelevanz(BaseModel): @@ -592,6 +592,7 @@ class Grunderfassung_Kontaktperson(BaseModel): class Grunderfassung_Stammdaten(BaseModel): model_config = ConfigDict(str_strip_whitespace=True) + kanal_aufmerksamkeit: str | None titel: str | None anrede_anschrift: str name: str diff --git a/src/wce_crm/db.py b/src/wce_crm/db.py index d5450b3..2b4b231 100644 --- a/src/wce_crm/db.py +++ b/src/wce_crm/db.py @@ -397,19 +397,6 @@ t_grunderfassung_personen: Table = Table( UTCDateTime, nullable=True, ), - # Column( - # "Metadaten_erstellung", - # UTCDateTime, - # nullable=True, - # default=lambda: datetime.datetime.now(datetime.UTC), - # ), - # Column( - # "Metadaten_aktualisierung", - # UTCDateTime, - # nullable=True, - # default=lambda: datetime.datetime.now(datetime.UTC), - # onupdate=lambda: datetime.datetime.now(datetime.UTC), - # ), Column("Metadaten_nutzer", sa.String(20), nullable=True), Column("Metadaten_wiedereintrittsdatum", sa.Date, nullable=True, default=None), Column("Arbeitserfahrung", sa.Text, nullable=True), @@ -423,15 +410,14 @@ t_grunderfassung_personen: Table = Table( Column("Kontaktperson__KP_funktion_beziehung", sa.Text, nullable=True), Column("Kontaktperson__KP_mobilfunknummer", sa.Text, nullable=True), Column("Kontaktperson__KP_name", sa.Text, nullable=True), - Column( - "Kontaktperson__KP_name_partner", sa.Text, nullable=True - ), # TODO: check if needed when set by trigger + Column("Kontaktperson__KP_name_partner", sa.Text, nullable=True), Column("Kontaktperson__KP_titel", sa.Text, nullable=True), Column("Kontaktperson__KP_vorname", sa.Text, nullable=True), Column("Projektrelevanz__relevanz", sa.Text, nullable=True), Column("Projektrelevanz__foerderperiode", sa.Text, nullable=True), Column("Schulbildung", sa.Text, nullable=True), Column("Sprachkenntnisse", sa.Text, nullable=True), + Column("Stammdaten__kanal_aufmerksamkeit", sa.Text, nullable=True), Column("Stammdaten__PLZ", sa.Text, nullable=True), Column("Stammdaten__anrede_anschrift", sa.Text, nullable=True), Column("Stammdaten__anzahl_kinder__alter", sa.Text, nullable=True), @@ -490,18 +476,7 @@ t_zuordnung_personen_unternehmen: Table = Table( UTCDateTime, nullable=True, ), - Column("Partnersuche__kanal_aufmerksamkeit", sa.Text, nullable=True), - # Column( - # "gueltig_ab", - # UTCDateTime, - # nullable=False, - # default=lambda: datetime.datetime.now(datetime.UTC), - # ), - # Column( - # "gueltig_bis", - # UTCDateTime, - # nullable=True, - # ), + Column("Partnersuche__kontaktweg", sa.Text, nullable=True), Index( "uq_aktive_zuordnung", "un_id", diff --git a/src/wce_crm/form_defs.py b/src/wce_crm/form_defs.py index 59e8005..aa476d5 100644 --- a/src/wce_crm/form_defs.py +++ b/src/wce_crm/form_defs.py @@ -307,53 +307,38 @@ _INITREC_COMP_SEARCH_HEAD = [ info="an_position", ), FormField( - "Wie sind Sie auf uns aufmerksam geworden?", + "Kontaktweg", FormFieldType.DROPDOWN, required=False, - key="kanal_aufmerksamkeit", + key="kontaktweg", options=[ - ("Agentur für Arbeit", None), - ("Ausländerbehörde", None), - ("Jobcenter", None), - ("Freunde/Familie", None), - ("Anerkennungsstelle", None), - ("Beratungsstelle", None), - ("Internet", None), - ("Arbeitgeber", None), - ("Bildungsdienstleister", None), - ("Welcome-Mappe", None), - ("Newsletter WFE", None), - ("Newsletter RM", None), - ("Sonstiges", None), + ("Telefon", None), + ("Mail", None), + ("Persönliches Gespräch", None), ], ), ] _INITREC_CONTACT_PERSON = [ - # TODO check removal FormField( - "Name Unternehmen/Netzwerkpartner (vorausgefüllt von Suche)", + "Name Unternehmen/Netzwerkpartner", FormFieldType.TEXT, key="KP_name_partner", required=False, - placeholder="[TODO: Logik in Verbindung mit Unternehmen unklar]", - readonly=True, + readonly=False, ), FormField( "Titel", FormFieldType.TEXT, key="KP_titel", required=False, - tooltip=( - "* nur wenn anrufende Person oder kontaktaufnehmende Person " - "nicht die zu beratende Person ist" - ), ), FormField( - "Anrede_Anschrift", - FormFieldType.TEXT, + "Anrede", + FormFieldType.DROPDOWN, key="KP_anrede_anschrift", required=True, + options=[("Sehr geehrte Frau", None), ("Sehr geehrter Herr", None)], ), FormField( "Name", @@ -401,21 +386,39 @@ _INITREC_CONTACT_PERSON = [ _INITREC_MASTER_DATA = [ + FormField( + "Wie sind Sie auf uns aufmerksam geworden?", + FormFieldType.DROPDOWN, + required=False, + key="kanal_aufmerksamkeit", + options=[ + ("Agentur für Arbeit", None), + ("Ausländerbehörde", None), + ("Jobcenter", None), + ("Freunde/Familie", None), + ("Anerkennungsstelle", None), + ("Beratungsstelle", None), + ("Internet", None), + ("Arbeitgeber", None), + ("Bildungsdienstleister", None), + ("Welcome-Mappe", None), + ("Newsletter WFE", None), + ("Newsletter RM", None), + ("Sonstiges", None), + ], + ), FormField( "Titel", FormFieldType.TEXT, key="titel", required=False, - tooltip=( - "* nur wenn anrufende Person oder kontaktaufnehmende Person " - "nicht die zu beratende Person ist" - ), ), FormField( "Anrede", - FormFieldType.TEXT, + FormFieldType.DROPDOWN, key="anrede_anschrift", required=True, + options=[("Sehr geehrte Frau", None), ("Sehr geehrter Herr", None)], ), FormField( "Name", @@ -427,17 +430,13 @@ _INITREC_MASTER_DATA = [ "Vorname", FormFieldType.TEXT, key="vorname", - required=False, + required=True, ), FormField( "Geburtsdatum", FormFieldType.DATE, key="geburtsdatum", required=False, - tooltip=( - "* Wichtig zu erfragen, da u.a. Mindestgehaltsschwelle davon abhängt " - "(Regelung bei Ü45 Jahre)" - ), ), FormField( "Herkunftsland", @@ -446,7 +445,6 @@ _INITREC_MASTER_DATA = [ required=True, placeholder="Suche...", options=COUNTRY_LIST.for_dropdown, - tooltip=("* Wichtig zu erfragen aufgrund eventueller EU-Freizügigkeitsregelung"), ), FormField( "Staatsangehörigkeit", @@ -455,7 +453,6 @@ _INITREC_MASTER_DATA = [ required=False, placeholder="Suche...", options=COUNTRY_LIST.for_dropdown, - tooltip=("* Wichtig zu erfragen aufgrund eventueller EU-Freizügigkeitsregelung"), ), FormField( "Rückkehrer", @@ -463,7 +460,6 @@ _INITREC_MASTER_DATA = [ key="rueckkehrer", required=False, options=[("ja", None), ("nein", None)], - tooltip=("* Wichtig zu erfragen aufgrund eventueller EU-Freizügigkeitsregelung"), ), FormField( "Wo befindet sich die Person?", @@ -502,7 +498,6 @@ _INITREC_MASTER_DATA = [ key="bundesland", required=False, options=GERMAN_STATE_LIST.for_dropdown, - tooltip=("nur wenn Inland angegeben"), ), FormField( "Land", @@ -535,13 +530,11 @@ _INITREC_MASTER_DATA = [ FormFieldType.TEXT, key="familienstand", required=False, - tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung", ), FormField( "Anzahl Kinder", FormFieldType.DYNAMIC_DROPDOWN_NUMERIC, required=False, - tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung", key="anzahl_kinder", children=[ FormField( @@ -549,7 +542,6 @@ _INITREC_MASTER_DATA = [ FormFieldType.DROPDOWN, required=False, options=[(str(x), None) for x in range(11)], - tooltip="* Wichtig zu erfragen aufgrund Lebensunterhaltssicherung", key="anzahl", children=[ FormField("Alter Kind", FormFieldType.TEXT, key="alter"), @@ -593,7 +585,6 @@ _INITREC_ADDITIONAL_DATA = [ ("Chancenaufenthaltsrecht §104c AufenthG", None), ("Sonstiges", None), ], - tooltip="sofern nicht bekannt, unbedingt einfordern", ), FormField( "Gültigkeit Aufenthaltsstatus", @@ -685,10 +676,6 @@ _INITREC_HIGHER_EDUCATION = [ FormFieldType.TEXT, required=False, key="HB_abschlussgrad", - tooltip=( - "bitte den Titel eingeben z.B. Doktor, Diplom oder " - "Betriebswirt (Fachschulabschluss)" - ), ), FormField( "Abschlussgrad laut Dokument", @@ -707,10 +694,6 @@ _INITREC_HIGHER_EDUCATION = [ FormFieldType.TEXT, required=False, key="HB_beruf", - tooltip=( - "bitte spezifizieren z.B. Allgemeinmedizin, Ingenieur Maschinenbau, " - "technischer Betriebswirt Datenverarbeitung" - ), ), FormField( "Land", @@ -737,7 +720,6 @@ _INITREC_HIGHER_EDUCATION = [ FormFieldType.TEXT, required=False, key="HB_bemerkungsfeld", - tooltip="z.B. Promotionen oder den Studiengang angeben", ), ] @@ -824,7 +806,6 @@ _INITREC_WORK_EXPERIENCE = [ ("Teilzeit", None), ("Sonstiges", None), ], - tooltip="Minijob, Praktikum, Wehrdienst, soziale Dienste", ), FormField( "Bemerkungsfeld", @@ -889,42 +870,6 @@ _INITREC_LANGUAGES = [ INITREC_COMP = [ - # FormField( - # "Ersteintrag Datum", - # FormFieldType.TEXT_DATETIME, - # required=False, - # key="Metadaten_erstellung", - # readonly=True, - # ignore_get_data=True, - # ), - # FormField( - # "Aktualisierung Datum", - # FormFieldType.TEXT_DATETIME, - # required=False, - # key="Metadaten_aktualisierung", - # readonly=True, - # ignore_get_data=True, - # ), - # FormField( - # "Aktualisierung Nutzer", - # FormFieldType.TEXT, - # required=False, - # key="Metadaten_nutzer", - # readonly=True, - # ignore_get_data=True, - # ), - # FormField( - # "Fallnummer", - # FormFieldType.TEXT, - # required=True, - # key="Grunderfassung_fallnummer", - # ), - # FormField( - # "Notizen", - # FormFieldType.LONGTEXT, - # required=False, - # key="Grunderfassung_notiz", - # ), FormField( "Suche", FormFieldType.CUSTOM, @@ -981,49 +926,6 @@ INITREC_METADATEN = [ ] INITREC_PERSON = [ - # FormField( - # "Ersteintrag Datum", - # FormFieldType.TEXT_DATETIME, - # required=False, - # key="Metadaten_erstellung", - # readonly=True, - # ignore_get_data=True, - # ), - # FormField( - # "Aktualisierung Datum", - # FormFieldType.TEXT_DATETIME, - # required=False, - # key="Metadaten_aktualisierung", - # readonly=True, - # ignore_get_data=True, - # ), - # FormField( - # "Aktualisierung Nutzer", - # FormFieldType.TEXT, - # required=False, - # key="Metadaten_nutzer", - # readonly=True, - # ignore_get_data=False, - # ), - # FormField( - # "Wiedereintrittsdatum", - # FormFieldType.DATE, - # required=False, - # key="Metadaten_wiedereintrittsdatum", - # readonly=False, - # ), - # FormField( - # "Fallnummer", - # FormFieldType.TEXT, - # required=True, - # key="Grunderfassung_fallnummer", - # ), - # FormField( - # "Notizen", - # FormFieldType.LONGTEXT, - # required=False, - # key="Grunderfassung_notiz", - # ), FormField( "Status && Projektrelevanz", FormFieldType.GROUP, diff --git a/src/wce_crm/gui.py b/src/wce_crm/gui.py index e3cf0cb..75e9bad 100644 --- a/src/wce_crm/gui.py +++ b/src/wce_crm/gui.py @@ -1142,15 +1142,15 @@ class Grunderfassung_SuchWidget(CustomFormWidget): self.person_search_input = cast(QComboBox, lookup[0]["widget"]) self.person_search_input.currentIndexChanged.connect(self._selected_person) - self.CHANNEL_AWARENESS_KEY = "kanal_aufmerksamkeit" - lookup = search_widgets_by_key(self.widget_registry, self.CHANNEL_AWARENESS_KEY) + self.CHANNEL_CONTACT_KEY = "kontaktweg" + lookup = search_widgets_by_key(self.widget_registry, self.CHANNEL_CONTACT_KEY) assert len(lookup) == 1 - self.channel_awareness = cast(QComboBox, lookup[0]["widget"]) + self.channel_contact = cast(QComboBox, lookup[0]["widget"]) self.DATA_EXPORT_FIELDS = ( self.COMPANY_SEARCH_INPUT_KEY, self.PERSON_SEARCH_INPUT_KEY, - self.CHANNEL_AWARENESS_KEY, + self.CHANNEL_CONTACT_KEY, ) self.company_widgets: dict[str, QWidget] = {} @@ -1234,7 +1234,7 @@ class Grunderfassung_SuchWidget(CustomFormWidget): def _clear_company_fields(self) -> None: self.person_search_input.clear() - self.channel_awareness.setCurrentIndex(0) + self.channel_contact.setCurrentIndex(0) for widget in self.company_widgets.values(): widget = cast(QLineEdit, widget) widget.clear() @@ -3473,8 +3473,6 @@ class Page_InitRec(QWidget): # TODO saving logic to connect company and person if needed def _reset(self) -> None: - # TODO change to make these calls implicit in child modules via - # TODO staes for form in self.STATE.child_modules: form.reset_form() self.STATE.ids = EntityIds() @@ -3494,9 +3492,9 @@ class Page_InitRec(QWidget): pers_id=5, ) - # ids = EntityIds( - # link_id=7, - # ) + ids = EntityIds( + link_id=7, + ) self.STATE.ids.update(ids, ignore_none=False) if ids.empty(): @@ -3752,7 +3750,6 @@ class Page_InitRec(QWidget): try: logger_page_initrec.debug("[Page -- InitRec] Call Pydantic...") - # validated_data = self.cfg.pydantic_model(**form_data) for ent_type, state in self.STATE.initrec_form_states.items(): logger_page_initrec.debug(