generated from dopt-python/py311
312 lines
9.1 KiB
Python
312 lines
9.1 KiB
Python
from __future__ import annotations
|
|
|
|
import datetime
|
|
from typing import TYPE_CHECKING, Any, cast
|
|
|
|
import polars as pl
|
|
import sqlalchemy as sql
|
|
|
|
from wce_crm import db
|
|
from wce_crm.constants import TIMEZONE_CEST
|
|
from wce_crm.logging import logger_back as logger
|
|
from wce_crm.types import CompanyInfo, ContactPersonInfo, InitRecType, MainPageEntry
|
|
|
|
if TYPE_CHECKING:
|
|
from wce_crm.types import ExtAnId, ExtMaId, RecId
|
|
|
|
|
|
def _transform_for_gui_output(
|
|
data: pl.DataFrame,
|
|
) -> pl.DataFrame:
|
|
q = (
|
|
data.lazy()
|
|
.with_columns(
|
|
pl.col(pl.Datetime).dt.to_string("%d.%m.%Y"),
|
|
pl.col(pl.Date).dt.to_string("%d.%m.%Y"),
|
|
pl.when(pl.col(pl.Boolean))
|
|
.then(pl.lit("Ja"))
|
|
.otherwise(pl.lit("Nein"))
|
|
.name.keep(),
|
|
)
|
|
.with_columns(pl.all().cast(pl.String))
|
|
)
|
|
|
|
return q.collect()
|
|
|
|
|
|
def initrec_comp_search_choices() -> tuple[tuple[str, int], ...]:
|
|
# TODO no reload functionality
|
|
logger.debug("[Call backend] comp_search_choices")
|
|
q = db.DF_CRM_MASTER.lazy()
|
|
counter = pl.int_range(0, pl.len()).over(pl.col.ma_unternehmensname)
|
|
q = q.with_columns(
|
|
dedupl=pl.when(counter == 0)
|
|
.then(pl.col.ma_unternehmensname)
|
|
.otherwise(pl.format("{} ({})", pl.col.ma_unternehmensname, counter))
|
|
)
|
|
df = q.collect()
|
|
|
|
return tuple(zip(df["dedupl"], df["ma_id"]))
|
|
|
|
|
|
def initrec_comp_search_get_info(
|
|
ma_id: ExtMaId,
|
|
) -> CompanyInfo:
|
|
logger.debug("[Call backend] comp_search_get_info")
|
|
df = db.DF_CRM_MASTER.filter(pl.col.ma_id == ma_id)
|
|
if df.height > 1 or df.height == 0:
|
|
raise ValueError(f"Größe des zurückgelieferten Datenpakets ungültig: {df.height}")
|
|
|
|
df = _transform_for_gui_output(df)
|
|
return cast(CompanyInfo, df.row(0, named=True))
|
|
|
|
|
|
def initrec_comp_contact_person_search_choices(
|
|
ma_id: ExtMaId | None,
|
|
use_both_names: bool,
|
|
) -> tuple[tuple[str, int], ...]:
|
|
# TODO no reload functionality
|
|
logger.debug("[Call backend] contact_person_search_choices")
|
|
q = db.DF_CONTACT_PERSON.lazy()
|
|
if ma_id is not None:
|
|
q = q.filter(pl.col.ma_id == ma_id)
|
|
|
|
dedupl_col = pl.col.an_nachname
|
|
if use_both_names:
|
|
q = q.with_columns(
|
|
name_search=(pl.format("{}, {}", pl.col.an_nachname, pl.col.an_vorname))
|
|
)
|
|
dedupl_col = pl.col.name_search
|
|
|
|
counter = pl.int_range(0, pl.len()).over(dedupl_col)
|
|
q = q.with_columns(
|
|
dedupl=pl.when(counter == 0)
|
|
.then(dedupl_col)
|
|
.otherwise(pl.format("{} ({})", dedupl_col, counter))
|
|
)
|
|
df = q.collect()
|
|
|
|
return tuple(zip(df["dedupl"], df["an_id"]))
|
|
|
|
|
|
def initrec_comp_contact_person_search_get_info(
|
|
an_id: ExtAnId,
|
|
) -> ContactPersonInfo:
|
|
logger.debug("[Call backend] contact_person_search_get_info")
|
|
df = db.DF_CONTACT_PERSON.filter(pl.col.an_id == an_id)
|
|
if df.height > 1 or df.height == 0:
|
|
raise ValueError(f"Größe des zurückgelieferten Datenpakets ungültig: {df.height}")
|
|
|
|
df = _transform_for_gui_output(df)
|
|
return cast(ContactPersonInfo, df.row(0, named=True))
|
|
|
|
|
|
# // internals
|
|
def initrec_company_insert_initial_recording(
|
|
data: dict[str, Any],
|
|
) -> RecId:
|
|
logger.debug("[Call backend] insert_initial_recording")
|
|
stmt = db.grunderfassung_unternehmen.insert()
|
|
with db.ENGINE.begin() as conn:
|
|
ret = conn.execute(stmt, data)
|
|
|
|
if ret.rowcount == 0:
|
|
raise IOError("Entry was not inserted correctly")
|
|
|
|
prim_keys = ret.inserted_primary_key
|
|
assert prim_keys
|
|
|
|
return prim_keys[0]
|
|
|
|
|
|
def initrec_company_update_initial_recording(
|
|
id_: RecId,
|
|
data: dict[str, Any],
|
|
) -> None:
|
|
logger.debug("[Call backend] update_initial_recording")
|
|
stmt = db.grunderfassung_unternehmen.update().where(
|
|
db.grunderfassung_unternehmen.c.un_id == id_
|
|
)
|
|
with db.ENGINE.begin() as conn:
|
|
conn.execute(stmt, data)
|
|
|
|
|
|
def initrec_company_get_initial_recording(
|
|
id_: RecId,
|
|
) -> dict[str, Any]:
|
|
logger.debug("[Call backend] get_initial_recording")
|
|
stmt = db.grunderfassung_unternehmen.select().where(
|
|
db.grunderfassung_unternehmen.c.un_id == id_
|
|
)
|
|
with db.ENGINE.begin() as conn:
|
|
ret = conn.execute(stmt)
|
|
|
|
if ret.rowcount == 0:
|
|
raise KeyError(f"Database ID {id_} not found")
|
|
|
|
row = ret.fetchone()
|
|
assert row, "row was not obtained"
|
|
|
|
return row._asdict()
|
|
|
|
|
|
def initrec_company_delete_initial_recording(
|
|
id_: RecId,
|
|
) -> None:
|
|
logger.debug("[Call backend] delete_initial_recording")
|
|
stmt = db.grunderfassung_unternehmen.delete().where(
|
|
db.grunderfassung_unternehmen.c.un_id == id_
|
|
)
|
|
with db.ENGINE.begin() as conn:
|
|
ret = conn.execute(stmt)
|
|
|
|
if ret.rowcount == 0:
|
|
raise KeyError(f"Database ID {id_} not found for deletion")
|
|
|
|
|
|
def initrec_person_insert_initial_recording(
|
|
data: dict[str, Any],
|
|
) -> RecId:
|
|
logger.debug("[Call backend] insert_initial_recording")
|
|
stmt = db.grunderfassung_personen.insert()
|
|
with db.ENGINE.begin() as conn:
|
|
ret = conn.execute(stmt, data)
|
|
|
|
if ret.rowcount == 0:
|
|
raise IOError("Entry was not inserted correctly")
|
|
|
|
prim_keys = ret.inserted_primary_key
|
|
assert prim_keys
|
|
|
|
return prim_keys[0]
|
|
|
|
|
|
def initrec_person_update_initial_recording(
|
|
id_: RecId,
|
|
data: dict[str, Any],
|
|
) -> None:
|
|
logger.debug("[Call backend] update_initial_recording")
|
|
stmt = db.grunderfassung_personen.update().where(
|
|
db.grunderfassung_personen.c.pers_id == id_
|
|
)
|
|
with db.ENGINE.begin() as conn:
|
|
conn.execute(stmt, data)
|
|
|
|
|
|
def initrec_person_get_initial_recording(
|
|
id_: RecId,
|
|
) -> dict[str, Any]:
|
|
logger.debug("[Call backend] get_initial_recording")
|
|
stmt = db.grunderfassung_personen.select().where(
|
|
db.grunderfassung_personen.c.pers_id == id_
|
|
)
|
|
with db.ENGINE.begin() as conn:
|
|
ret = conn.execute(stmt)
|
|
|
|
if ret.rowcount == 0:
|
|
raise KeyError(f"Database ID {id_} not found")
|
|
|
|
row = ret.fetchone()
|
|
assert row, "row was not obtained"
|
|
|
|
return row._asdict()
|
|
|
|
|
|
def initrec_person_delete_initial_recording(
|
|
id_: RecId,
|
|
) -> None:
|
|
logger.debug("[Call backend] delete_initial_recording")
|
|
stmt = db.grunderfassung_personen.delete().where(
|
|
db.grunderfassung_personen.c.pers_id == id_
|
|
)
|
|
with db.ENGINE.begin() as conn:
|
|
ret = conn.execute(stmt)
|
|
|
|
if ret.rowcount == 0:
|
|
raise KeyError(f"Database ID {id_} not found for deletion")
|
|
|
|
|
|
# // main page interaction
|
|
def _main_page_get_company_list() -> list[MainPageEntry]:
|
|
logger.debug("[Call backend] get_company_list")
|
|
stmt = sql.select(
|
|
db.grunderfassung_unternehmen.c.un_id,
|
|
db.grunderfassung_unternehmen.c.Partnersuche__un_suche,
|
|
db.grunderfassung_unternehmen.c.Metadaten_aktualisierung,
|
|
)
|
|
|
|
with db.ENGINE.connect() as conn:
|
|
res = conn.execute(stmt)
|
|
|
|
main_page_companies: list[MainPageEntry] = []
|
|
|
|
for entry in res.mappings():
|
|
rec_id = entry["un_id"]
|
|
assert rec_id, "no RecID defined"
|
|
ma_id_external = entry["Partnersuche__un_suche"]
|
|
assert ma_id_external is not None, "external MA ID is NULL"
|
|
datetime_akt = cast(datetime.datetime, entry["Metadaten_aktualisierung"])
|
|
datetime_akt = datetime_akt.astimezone(TIMEZONE_CEST)
|
|
|
|
comp_info = initrec_comp_search_get_info(ma_id_external)
|
|
display_name = comp_info["ma_unternehmensname"]
|
|
|
|
main_page_companies.append(
|
|
MainPageEntry(
|
|
rec_id=rec_id,
|
|
display_name=display_name,
|
|
Metadaten_aktualisierung=datetime_akt,
|
|
type=InitRecType.COMPANY,
|
|
)
|
|
)
|
|
|
|
return main_page_companies
|
|
|
|
|
|
def _main_page_get_person_list() -> list[MainPageEntry]:
|
|
logger.debug("[Call backend] get_company_list")
|
|
stmt = sql.select(
|
|
db.grunderfassung_personen.c.pers_id,
|
|
db.grunderfassung_personen.c.Stammdaten__vorname,
|
|
db.grunderfassung_personen.c.Stammdaten__name,
|
|
db.grunderfassung_personen.c.Metadaten_aktualisierung,
|
|
)
|
|
|
|
with db.ENGINE.connect() as conn:
|
|
res = conn.execute(stmt)
|
|
|
|
main_page_persons: list[MainPageEntry] = []
|
|
|
|
for entry in res.mappings():
|
|
rec_id = entry["pers_id"]
|
|
assert rec_id, "no RecID defined"
|
|
datetime_akt = cast(datetime.datetime, entry["Metadaten_aktualisierung"])
|
|
datetime_akt = datetime_akt.astimezone()
|
|
|
|
surname: str = entry["Stammdaten__name"]
|
|
first_name: str = entry["Stammdaten__vorname"]
|
|
names_to_join = [n for n in (first_name, surname) if n]
|
|
display_name = " ".join(names_to_join)
|
|
|
|
main_page_persons.append(
|
|
MainPageEntry(
|
|
rec_id=rec_id,
|
|
display_name=display_name,
|
|
Metadaten_aktualisierung=datetime_akt,
|
|
type=InitRecType.PERSON,
|
|
)
|
|
)
|
|
|
|
return main_page_persons
|
|
|
|
|
|
def main_page_get_entries() -> list[MainPageEntry]:
|
|
companies = _main_page_get_company_list()
|
|
persons = _main_page_get_person_list()
|
|
|
|
all_entries = companies + persons
|
|
|
|
all_entries.sort(key=lambda x: x.Metadaten_aktualisierung, reverse=True)
|
|
|
|
return all_entries
|