Kontaktadresse: Neues Feld Position, Filter-Funktionen null-sicher, Projektnamen-Spalte entfernt
- Server: Neue Spalte position in Kontaktadresse-Modell (String(200), nullable) - Server: Migration V01_04 (ALTER TABLE kontaktadressen ADD COLUMN position) - Server: position in Geschäftslogik create/update aufgenommen - Server: CLI-Musterdaten um Position ergänzt (Geschäftsführer, IT-Leiter etc.) - Client: position in iKontaktadresse-Interface, View nach Firma, Columnmapper, Filter - Client: Projektnamen-Spalte aus Kontaktadressenliste entfernt (steht in Überschrift) - Client: Filter-Funktionen in allen Listen null-sicher (kunde, kontakt, projekt, kontaktadresse, call_log) Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
1 parent
b510c50497
commit
e9a2f48ede
10 files changed
+59
-36
No files matched your search
@@ -164,11 +164,11 @@ def _seed_muster_kontaktadressen():
|
|||||||
|
|
||||||
projekte = session.query(Projekt).order_by(Projekt.id).all()
|
projekte = session.query(Projekt).order_by(Projekt.id).all()
|
||||||
vorlagen = [
|
vorlagen = [
|
||||||
("Herr", "Thomas Becker", "Becker Webdesign GmbH"),
|
("Herr", "Thomas Becker", "Becker Webdesign GmbH", "Geschäftsführer"),
|
||||||
("Frau", "Sandra Klein", "Klein Marketing"),
|
("Frau", "Sandra Klein", "Klein Marketing", "Marketingleiterin"),
|
||||||
("Herr", "Michael Wagner", "Wagner Online Shop"),
|
("Herr", "Michael Wagner", "Wagner Online Shop", "IT-Leiter"),
|
||||||
("Frau", "Julia Hoffmann", "Hoffmann Consulting"),
|
("Frau", "Julia Hoffmann", "Hoffmann Consulting", "Beraterin"),
|
||||||
("Herr", "Stefan Roth", "Roth IT Solutions"),
|
("Herr", "Stefan Roth", "Roth IT Solutions", "Technischer Leiter"),
|
||||||
]
|
]
|
||||||
orte = [
|
orte = [
|
||||||
("Industriestr. 12", "45131", "Essen", "Deutschland"),
|
("Industriestr. 12", "45131", "Essen", "Deutschland"),
|
||||||
@@ -181,7 +181,7 @@ def _seed_muster_kontaktadressen():
|
|||||||
for projekt in projekte:
|
for projekt in projekte:
|
||||||
anzahl = rng.randint(1, 3)
|
anzahl = rng.randint(1, 3)
|
||||||
for _ in range(anzahl):
|
for _ in range(anzahl):
|
||||||
anrede, name, firma = vorlagen[vorlagen_idx % len(vorlagen)]
|
anrede, name, firma, position = vorlagen[vorlagen_idx % len(vorlagen)]
|
||||||
vorlagen_idx += 1
|
vorlagen_idx += 1
|
||||||
strasse, plz, ort, land = rng.choice(orte)
|
strasse, plz, ort, land = rng.choice(orte)
|
||||||
ka = Kontaktadresse()
|
ka = Kontaktadresse()
|
||||||
@@ -189,6 +189,7 @@ def _seed_muster_kontaktadressen():
|
|||||||
ka.anrede = anrede
|
ka.anrede = anrede
|
||||||
ka.name = name
|
ka.name = name
|
||||||
ka.firma = firma
|
ka.firma = firma
|
||||||
|
ka.position = position
|
||||||
ka.telefon = "+49 {vorwahl} {nummer}".format(
|
ka.telefon = "+49 {vorwahl} {nummer}".format(
|
||||||
vorwahl=rng.randint(100, 999),
|
vorwahl=rng.randint(100, 999),
|
||||||
nummer=rng.randint(100000, 999999)
|
nummer=rng.randint(100000, 999999)
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ class Kontaktadresse(dbapp.Model):
|
|||||||
anrede = Column(String(30), nullable=True)
|
anrede = Column(String(30), nullable=True)
|
||||||
name = Column(String(200), nullable=False)
|
name = Column(String(200), nullable=False)
|
||||||
firma = Column(String(200), nullable=True)
|
firma = Column(String(200), nullable=True)
|
||||||
|
position = Column(String(200), nullable=True)
|
||||||
telefon = Column(String(100), nullable=True)
|
telefon = Column(String(100), nullable=True)
|
||||||
email = Column(String(200), nullable=True)
|
email = Column(String(200), nullable=True)
|
||||||
strasse = Column(String(200), nullable=True)
|
strasse = Column(String(200), nullable=True)
|
||||||
|
|||||||
@@ -78,6 +78,19 @@ def _db_V01_03():
|
|||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def _db_V01_04():
|
||||||
|
"""
|
||||||
|
Fügt die Spalte 'position' zur Tabelle 'kontaktadressen' hinzu.
|
||||||
|
Bei bestehenden Datenbanken, die mit Version 01.03 initialisiert wurden,
|
||||||
|
fehlt diese Spalte, da das Feld erst nachträglich ergänzt wurde.
|
||||||
|
"""
|
||||||
|
from sqlalchemy import text
|
||||||
|
|
||||||
|
session.execute(text("ALTER TABLE kontaktadressen ADD COLUMN position VARCHAR(200)"))
|
||||||
|
_updatesysteminfo('01.04')
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
def checkupdates():
|
def checkupdates():
|
||||||
"""
|
"""
|
||||||
Ermittelt die aktuelle DB-Version aus der Systeminfo-Tabelle und führt alle
|
Ermittelt die aktuelle DB-Version aus der Systeminfo-Tabelle und führt alle
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ def create_kontaktadresse(data: dict) -> Kontaktadresse:
|
|||||||
kontaktadresse.anrede = (data.get("anrede") or "").strip() or None
|
kontaktadresse.anrede = (data.get("anrede") or "").strip() or None
|
||||||
kontaktadresse.name = data["name"].strip()
|
kontaktadresse.name = data["name"].strip()
|
||||||
kontaktadresse.firma = (data.get("firma") or "").strip() or None
|
kontaktadresse.firma = (data.get("firma") or "").strip() or None
|
||||||
|
kontaktadresse.position = (data.get("position") or "").strip() or None
|
||||||
kontaktadresse.telefon = (data.get("telefon") or "").strip() or None
|
kontaktadresse.telefon = (data.get("telefon") or "").strip() or None
|
||||||
kontaktadresse.email = (data.get("email") or "").strip() or None
|
kontaktadresse.email = (data.get("email") or "").strip() or None
|
||||||
kontaktadresse.strasse = (data.get("strasse") or "").strip() or None
|
kontaktadresse.strasse = (data.get("strasse") or "").strip() or None
|
||||||
@@ -107,6 +108,7 @@ def update_kontaktadresse(data: dict) -> Kontaktadresse:
|
|||||||
kontaktadresse.anrede = (data.get("anrede") or "").strip() or None
|
kontaktadresse.anrede = (data.get("anrede") or "").strip() or None
|
||||||
kontaktadresse.name = data["name"].strip()
|
kontaktadresse.name = data["name"].strip()
|
||||||
kontaktadresse.firma = (data.get("firma") or "").strip() or None
|
kontaktadresse.firma = (data.get("firma") or "").strip() or None
|
||||||
|
kontaktadresse.position = (data.get("position") or "").strip() or None
|
||||||
kontaktadresse.telefon = (data.get("telefon") or "").strip() or None
|
kontaktadresse.telefon = (data.get("telefon") or "").strip() or None
|
||||||
kontaktadresse.email = (data.get("email") or "").strip() or None
|
kontaktadresse.email = (data.get("email") or "").strip() or None
|
||||||
kontaktadresse.strasse = (data.get("strasse") or "").strip() or None
|
kontaktadresse.strasse = (data.get("strasse") or "").strip() or None
|
||||||
|
|||||||
@@ -74,14 +74,14 @@ export const call_log_liste: m.ClosureComponent = (vnode) => {
|
|||||||
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
||||||
let log: iCallLog = node.nodevalue
|
let log: iCallLog = node.nodevalue
|
||||||
let searchLower = searchvalue.toLowerCase()
|
let searchLower = searchvalue.toLowerCase()
|
||||||
return log.kunden_name.toLowerCase().includes(searchLower) ||
|
return (log.kunden_name || "").toLowerCase().includes(searchLower) ||
|
||||||
log.projekt_name.toLowerCase().includes(searchLower) ||
|
(log.projekt_name || "").toLowerCase().includes(searchLower) ||
|
||||||
log.datum.includes(searchLower) ||
|
(log.datum || "").includes(searchLower) ||
|
||||||
log.uhrzeit_beginn.toLowerCase().includes(searchLower) ||
|
(log.uhrzeit_beginn || "").toLowerCase().includes(searchLower) ||
|
||||||
log.betreff.toLowerCase().includes(searchLower) ||
|
(log.betreff || "").toLowerCase().includes(searchLower) ||
|
||||||
log.name_ansprechpartner.toLowerCase().includes(searchLower) ||
|
(log.name_ansprechpartner || "").toLowerCase().includes(searchLower) ||
|
||||||
log.notiz.toLowerCase().includes(searchLower) ||
|
(log.notiz || "").toLowerCase().includes(searchLower) ||
|
||||||
log.wiedervorlage_datum.includes(searchLower)
|
(log.wiedervorlage_datum || "").includes(searchLower)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ export const kontaktliste: m.ClosureComponent = (vnode) => {
|
|||||||
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
||||||
let kontakt: iKontakt = node.nodevalue
|
let kontakt: iKontakt = node.nodevalue
|
||||||
let searchLower = searchvalue.toLowerCase()
|
let searchLower = searchvalue.toLowerCase()
|
||||||
return kontakt.name.toLowerCase().includes(searchLower) ||
|
return (kontakt.name || "").toLowerCase().includes(searchLower) ||
|
||||||
kontakt.position.toLowerCase().includes(searchLower) ||
|
(kontakt.position || "").toLowerCase().includes(searchLower) ||
|
||||||
kontakt.telefon.toLowerCase().includes(searchLower) ||
|
(kontakt.telefon || "").toLowerCase().includes(searchLower) ||
|
||||||
kontakt.email.toLowerCase().includes(searchLower) ||
|
(kontakt.email || "").toLowerCase().includes(searchLower) ||
|
||||||
kontakt.kunden_name.toLowerCase().includes(searchLower)
|
(kontakt.kunden_name || "").toLowerCase().includes(searchLower)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -64,10 +64,10 @@ export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
|
|||||||
return [
|
return [
|
||||||
m("div", m("strong", kontaktadresse.name)),
|
m("div", m("strong", kontaktadresse.name)),
|
||||||
m("span", kontaktadresse.firma),
|
m("span", kontaktadresse.firma),
|
||||||
|
m("span", kontaktadresse.position),
|
||||||
m("span", kontaktadresse.telefon),
|
m("span", kontaktadresse.telefon),
|
||||||
m("span", kontaktadresse.email),
|
m("span", kontaktadresse.email),
|
||||||
m("span", kontaktadresse.ort),
|
m("span", kontaktadresse.ort),
|
||||||
m("span", kontaktadresse.projekt_name),
|
|
||||||
m("div", {style: {display: 'flex', gap: '0', 'white-space': 'nowrap'}},
|
m("div", {style: {display: 'flex', gap: '0', 'white-space': 'nowrap'}},
|
||||||
m("button.w3-button.w3-small", {style: {padding: '0 2px'}, onclick: (e: Event) => editKontaktadresse(kontaktadresse, e)}, m("i.material-icons", "edit")),
|
m("button.w3-button.w3-small", {style: {padding: '0 2px'}, onclick: (e: Event) => editKontaktadresse(kontaktadresse, e)}, m("i.material-icons", "edit")),
|
||||||
m("button.w3-button.w3-small", {title: "Gesprächsnotiz hinzufügen", style: {padding: '0 2px'}, onclick: (e: Event) => addCallLog(kontaktadresse, e)}, m("i.material-icons", "add_call"))
|
m("button.w3-button.w3-small", {title: "Gesprächsnotiz hinzufügen", style: {padding: '0 2px'}, onclick: (e: Event) => addCallLog(kontaktadresse, e)}, m("i.material-icons", "add_call"))
|
||||||
@@ -78,12 +78,13 @@ export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
|
|||||||
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
||||||
let kontaktadresse: iKontaktadresse = node.nodevalue
|
let kontaktadresse: iKontaktadresse = node.nodevalue
|
||||||
let searchLower = searchvalue.toLowerCase()
|
let searchLower = searchvalue.toLowerCase()
|
||||||
return kontaktadresse.name.toLowerCase().includes(searchLower) ||
|
return (kontaktadresse.name || "").toLowerCase().includes(searchLower) ||
|
||||||
kontaktadresse.firma.toLowerCase().includes(searchLower) ||
|
(kontaktadresse.firma || "").toLowerCase().includes(searchLower) ||
|
||||||
kontaktadresse.telefon.toLowerCase().includes(searchLower) ||
|
(kontaktadresse.position || "").toLowerCase().includes(searchLower) ||
|
||||||
kontaktadresse.email.toLowerCase().includes(searchLower) ||
|
(kontaktadresse.telefon || "").toLowerCase().includes(searchLower) ||
|
||||||
kontaktadresse.ort.toLowerCase().includes(searchLower) ||
|
(kontaktadresse.email || "").toLowerCase().includes(searchLower) ||
|
||||||
kontaktadresse.projekt_name.toLowerCase().includes(searchLower)
|
(kontaktadresse.ort || "").toLowerCase().includes(searchLower) ||
|
||||||
|
(kontaktadresse.projekt_name || "").toLowerCase().includes(searchLower)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -152,6 +153,7 @@ export const Kontaktadresse: m.ClosureComponent = (vnode) => {
|
|||||||
anrede: string
|
anrede: string
|
||||||
name: string
|
name: string
|
||||||
firma: string
|
firma: string
|
||||||
|
position: string
|
||||||
telefon: string
|
telefon: string
|
||||||
email: string
|
email: string
|
||||||
strasse: string
|
strasse: string
|
||||||
@@ -166,6 +168,7 @@ export const Kontaktadresse: m.ClosureComponent = (vnode) => {
|
|||||||
anrede: "",
|
anrede: "",
|
||||||
name: "",
|
name: "",
|
||||||
firma: "",
|
firma: "",
|
||||||
|
position: "",
|
||||||
telefon: "",
|
telefon: "",
|
||||||
email: "",
|
email: "",
|
||||||
strasse: "",
|
strasse: "",
|
||||||
@@ -200,6 +203,7 @@ export const Kontaktadresse: m.ClosureComponent = (vnode) => {
|
|||||||
anrede: (formData.get("anrede") as string) || "",
|
anrede: (formData.get("anrede") as string) || "",
|
||||||
name: (formData.get("name") as string) || "",
|
name: (formData.get("name") as string) || "",
|
||||||
firma: (formData.get("firma") as string) || "",
|
firma: (formData.get("firma") as string) || "",
|
||||||
|
position: (formData.get("position") as string) || "",
|
||||||
telefon: (formData.get("telefon") as string) || "",
|
telefon: (formData.get("telefon") as string) || "",
|
||||||
email: (formData.get("email") as string) || "",
|
email: (formData.get("email") as string) || "",
|
||||||
strasse: (formData.get("strasse") as string) || "",
|
strasse: (formData.get("strasse") as string) || "",
|
||||||
@@ -228,6 +232,7 @@ export const Kontaktadresse: m.ClosureComponent = (vnode) => {
|
|||||||
m("label", "Anrede", m(Input, {name: "anrede", value: currentKontaktadresse.anrede, type: "text"} as iInput)),
|
m("label", "Anrede", m(Input, {name: "anrede", value: currentKontaktadresse.anrede, type: "text"} as iInput)),
|
||||||
m("label", "Name", m(Input, {name: "name", value: currentKontaktadresse.name, type: "text", required: true} as iInput)),
|
m("label", "Name", m(Input, {name: "name", value: currentKontaktadresse.name, type: "text", required: true} as iInput)),
|
||||||
m("label", "Firma", m(Input, {name: "firma", value: currentKontaktadresse.firma, type: "text"} as iInput)),
|
m("label", "Firma", m(Input, {name: "firma", value: currentKontaktadresse.firma, type: "text"} as iInput)),
|
||||||
|
m("label", "Position", m(Input, {name: "position", value: currentKontaktadresse.position, type: "text"} as iInput)),
|
||||||
m("label", "Telefon", m(Input, {name: "telefon", value: currentKontaktadresse.telefon, type: "tel"} as iInput)),
|
m("label", "Telefon", m(Input, {name: "telefon", value: currentKontaktadresse.telefon, type: "tel"} as iInput)),
|
||||||
m("label", "E-Mail", m(Input, {name: "email", value: currentKontaktadresse.email, type: "email"} as iInput)),
|
m("label", "E-Mail", m(Input, {name: "email", value: currentKontaktadresse.email, type: "email"} as iInput)),
|
||||||
m("label", "Straße", m(Input, {name: "strasse", value: currentKontaktadresse.strasse, type: "text"} as iInput)),
|
m("label", "Straße", m(Input, {name: "strasse", value: currentKontaktadresse.strasse, type: "text"} as iInput)),
|
||||||
|
|||||||
@@ -117,11 +117,11 @@ export const kundenliste: m.ClosureComponent = (vnode) => {
|
|||||||
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
||||||
let kunde: iKunde = node.nodevalue
|
let kunde: iKunde = node.nodevalue
|
||||||
let searchLower = searchvalue.toLowerCase()
|
let searchLower = searchvalue.toLowerCase()
|
||||||
return kunde.name.toLowerCase().includes(searchLower) ||
|
return (kunde.name || "").toLowerCase().includes(searchLower) ||
|
||||||
kunde.strasse.toLowerCase().includes(searchLower) ||
|
(kunde.strasse || "").toLowerCase().includes(searchLower) ||
|
||||||
kunde.plz.includes(searchLower) ||
|
(kunde.plz || "").includes(searchLower) ||
|
||||||
kunde.ort.toLowerCase().includes(searchLower) ||
|
(kunde.ort || "").toLowerCase().includes(searchLower) ||
|
||||||
kunde.land.toLowerCase().includes(searchLower)
|
(kunde.land || "").toLowerCase().includes(searchLower)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -91,11 +91,11 @@ export const projektliste: m.ClosureComponent = (vnode) => {
|
|||||||
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
const filterFunction = (node: iTreenode, searchvalue: string): boolean => {
|
||||||
let projekt: iProjekt = node.nodevalue
|
let projekt: iProjekt = node.nodevalue
|
||||||
let searchLower = searchvalue.toLowerCase()
|
let searchLower = searchvalue.toLowerCase()
|
||||||
return projekt.kunden_name.toLowerCase().includes(searchLower) ||
|
return (projekt.kunden_name || "").toLowerCase().includes(searchLower) ||
|
||||||
projekt.projektname.toLowerCase().includes(searchLower) ||
|
(projekt.projektname || "").toLowerCase().includes(searchLower) ||
|
||||||
projekt.zweck.toLowerCase().includes(searchLower) ||
|
(projekt.zweck || "").toLowerCase().includes(searchLower) ||
|
||||||
projekt.verantwortlicher.toLowerCase().includes(searchLower) ||
|
(projekt.verantwortlicher || "").toLowerCase().includes(searchLower) ||
|
||||||
projekt.startdatum.includes(searchLower)
|
(projekt.startdatum || "").includes(searchLower)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export interface iKontaktadresse {
|
|||||||
anrede: string
|
anrede: string
|
||||||
name: string
|
name: string
|
||||||
firma: string
|
firma: string
|
||||||
|
position: string
|
||||||
telefon: string
|
telefon: string
|
||||||
email: string
|
email: string
|
||||||
strasse: string
|
strasse: string
|
||||||
|
|||||||
Reference in new issue
Block a user