Validate applicant and call database procedure

This commit is contained in:
Yuri Becker
2025-04-15 15:24:31 +02:00
parent a720dfebeb
commit f0382a960e
15 changed files with 149 additions and 74 deletions

View File

@@ -6,23 +6,38 @@ ColumnLayout {
anchors.fill: parent anchors.fill: parent
spacing: Dimensions.l spacing: Dimensions.l
Component.onCompleted: {
employee_model.addedNewEmployee.connect(successful => {
if (successful)
contentStack.pop();
});
}
ApplicantForm { ApplicantForm {
id: applicantForm
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.fillHeight: true Layout.fillHeight: true
Layout.verticalStretchFactor: 1 Layout.verticalStretchFactor: 1
} }
RowLayout { RowLayout {
spacing: Dimensions.l
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
spacing: Dimensions.l
Button { Button {
icon.source: "qrc:/images/ArrowLeftCircle-Outline.svg" icon.source: "qrc:/images/ArrowLeftCircle-Outline.svg"
text: qsTr("Verwerfen") text: qsTr("Verwerfen")
}
onClicked: contentStack.pop()
}
Button { Button {
enabled: applicantForm.valid
icon.source: "qrc:/images/CheckCircle.svg" icon.source: "qrc:/images/CheckCircle.svg"
text: qsTr("Speichern") text: qsTr("Speichern")
onClicked: {
employee_model.addApplicant(applicantForm.value);
}
} }
} }
} }

View File

@@ -7,15 +7,10 @@ ColumnLayout {
id: colPar id: colPar
function checkFields() { function checkFields() {
if (radio.children[1].checked) {
if (!personalData.checkPersonalField()) if (!personalData.checkPersonalField())
saveBtn.enabled = false; saveBtn.enabled = false;
else else
saveBtn.enabled = true; saveBtn.enabled = true;
} else if (!personalData.checkPersonalField())
saveBtn.enabled = false;
else
saveBtn.enabled = true;
} }
function onAddNewEmployee(added) { function onAddNewEmployee(added) {
if (added) if (added)
@@ -49,20 +44,6 @@ ColumnLayout {
personalData.requiredField(); personalData.requiredField();
} }
} }
Row {
id: radio
Layout.fillWidth: true
//Layout.columnSpan: 2
RadioButton {
checked: true
text: qsTr("Bewerber")
}
RadioButton {
text: qsTr("Mitarbeiter")
}
}
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: 50 spacing: 50
@@ -121,22 +102,8 @@ ColumnLayout {
text: qsTr("Speichern") text: qsTr("Speichern")
onClicked: { onClicked: {
var new_applicant; const new_applicant = JsLib.parseForm(personalData, bankAccount, nationalInsurance, applicantVarious);
if (radio.children[0].checked) {
// Ein Bewerber
new_applicant = JsLib.parseForm(personalData);
employee_model.addEmployee(new_applicant, true);
// appLoader.source = "EmployeeTable.qml"
// console.log(JSON.stringify (new_applicant))
} else {
// Ein Mitarbeiter
// console.log(personalData, bankAccount, nationalInsurance, applicantVarious)
new_applicant = JsLib.parseForm(personalData, bankAccount, nationalInsurance, applicantVarious);
employee_model.addEmployee(new_applicant, false); employee_model.addEmployee(new_applicant, false);
// var new_contact = JsLib.addApplicant(addContactLayout)
// contact_model.addContact(new_contact)
// console.log(JSON.stringify (new_applicant))
}
} }
} }
} }

View File

@@ -6,6 +6,20 @@ import TeroStyle
ColumnLayout { ColumnLayout {
readonly property int fieldM: 235 readonly property int fieldM: 235
readonly property int fieldS: 110 readonly property int fieldS: 110
readonly property bool valid: city.acceptableInput && email.acceptableInput && firstname.acceptableInput && lastname.acceptableInput && mobile.acceptableInput && phone.acceptableInput && postcode.acceptableInput && formofaddress.acceptableInput && title.acceptableInput
readonly property var value: QtObject {
readonly property string city: (city.editText ? city.editText : city.currentText) ?? ""
readonly property string email: email.text
readonly property string firstname: firstname.text
readonly property string formofaddress: formofaddress.currentText ?? ""
readonly property string houseno: houseno.text ?? ""
readonly property string lastname: lastname.text
readonly property string mobile: mobile.text
readonly property string phone: phone.text
readonly property string postcode: (postcode.editText ? postcode.editText : postcode.currentText) ?? ""
readonly property string street: (street.editText ? street.editText : street.currentText) ?? ""
readonly property string title: title.currentText
}
spacing: Dimensions.l spacing: Dimensions.l
@@ -34,31 +48,43 @@ ColumnLayout {
onCurrentTextChanged: { onCurrentTextChanged: {
switch (title.currentIndex) { switch (title.currentIndex) {
case 1: case 1:
salutation.text = "Sehr geehrter Herr "; formofaddress.text = "Sehr geehrter Herr ";
break; break;
case 2: case 2:
salutation.text = "Sehr geehrte Frau "; formofaddress.text = "Sehr geehrte Frau ";
break; break;
default: default:
salutation.text = "Guten Tag "; formofaddress.text = "Guten Tag ";
} }
} }
} }
} }
Field { Field {
label: qsTr("Vorname*") label: qsTr("Vorname")
mandatory: true
TextField { TextField {
id: firstname
implicitWidth: fieldM implicitWidth: fieldM
placeholderText: "Max" placeholderText: qsTr("Max")
validator: NotEmptyValidator {
}
} }
} }
Field { Field {
label: qsTr("Nachname*") label: qsTr("Nachname")
mandatory: true
TextField { TextField {
id: lastname
implicitWidth: fieldM implicitWidth: fieldM
placeholderText: qsTr("Mustermann") placeholderText: qsTr("Mustermann")
validator: NotEmptyValidator {
}
} }
} }
} }
@@ -66,6 +92,8 @@ ColumnLayout {
spacing: Dimensions.m spacing: Dimensions.m
Field { Field {
id: street
label: qsTr("Straße") label: qsTr("Straße")
TextField { TextField {
@@ -74,6 +102,8 @@ ColumnLayout {
} }
} }
Field { Field {
id: houseno
label: qsTr("Hausnummer") label: qsTr("Hausnummer")
TextField { TextField {
@@ -86,6 +116,8 @@ ColumnLayout {
ComboBox { ComboBox {
id: postcode id: postcode
currentIndex: -1
editable: true editable: true
implicitWidth: fieldS implicitWidth: fieldS
model: address_model model: address_model
@@ -97,14 +129,19 @@ ColumnLayout {
} }
Field { Field {
label: qsTr("Ort") label: qsTr("Ort")
mandatory: true
ComboBox { ComboBox {
id: city id: city
currentIndex: -1
editable: true editable: true
implicitWidth: fieldM implicitWidth: fieldM
model: address_model model: address_model
textRole: "city" textRole: "city"
validator: NotEmptyValidator {
}
} }
} }
} }
@@ -125,10 +162,12 @@ ColumnLayout {
label: qsTr("Telefonnummer") label: qsTr("Telefonnummer")
TextField { TextField {
id: phone
implicitWidth: fieldM implicitWidth: fieldM
placeholderText: "+49 1234 567890" placeholderText: "+49 1234 567890"
validator: PhoneNumberValidator { validator: OptionalPhoneNumberValidator {
} }
} }
} }
@@ -136,10 +175,12 @@ ColumnLayout {
label: qsTr("Mobil") label: qsTr("Mobil")
TextField { TextField {
id: mobile
implicitWidth: fieldM implicitWidth: fieldM
placeholderText: "+49 123 4567891011" placeholderText: "+49 123 4567891011"
validator: PhoneNumberValidator { validator: OptionalPhoneNumberValidator {
} }
} }
} }
@@ -147,10 +188,12 @@ ColumnLayout {
label: qsTr("E-Mail Adresse") label: qsTr("E-Mail Adresse")
TextField { TextField {
id: email
implicitWidth: fieldM implicitWidth: fieldM
placeholderText: "tero@example.org" placeholderText: "tero@example.org"
validator: EmailAddressValidator { validator: OptionalEmailAddressValidator {
} }
} }
} }
@@ -158,7 +201,7 @@ ColumnLayout {
label: qsTr("Briefanrede") label: qsTr("Briefanrede")
TextField { TextField {
id: salutation id: formofaddress
implicitWidth: fieldM implicitWidth: fieldM
} }

View File

@@ -44,12 +44,12 @@ T.Button {
border.color: Colors.interactive border.color: Colors.interactive
border.width: isFieldButton ? 1 : 0 border.width: isFieldButton ? 1 : 0
bottomLeftRadius: topLeftRadius bottomLeftRadius: topLeftRadius
color: !control.hovered ? Colors.primary : Colors.primaryLighter color: !control.enabled ? Colors.disabled : !control.hovered ? Colors.primary : Colors.primaryLighter
radius: Dimensions.radius radius: Dimensions.radius
topLeftRadius: isFieldButton ? 0 : radius topLeftRadius: isFieldButton ? 0 : radius
} }
contentItem: I.IconLabel { contentItem: I.IconLabel {
color: Colors.primaryContrast color: !control.enabled ? Colors.disabledForeground : Colors.primaryContrast
display: control.display display: control.display
font: control.font font: control.font
icon: control.icon icon: control.icon

View File

@@ -17,6 +17,8 @@ QtObject {
readonly property color mantle: theme === dark ? "#1E1E23" : "#e7e9ef" readonly property color mantle: theme === dark ? "#1E1E23" : "#e7e9ef"
readonly property color interactive: theme === dark ? "#878b97" : "#d9d9da" readonly property color interactive: theme === dark ? "#878b97" : "#d9d9da"
readonly property color error: theme === dark ? "#ff2264" : "#ff004b" readonly property color error: theme === dark ? "#ff2264" : "#ff004b"
readonly property color disabled: theme === dark ? Qt.darker(interactive, 1.9) : Qt.darker(interactive, 1.3)
readonly property color disabledForeground: theme === dark ? Qt.darker(foreground, 1.4) : Qt.lighter(foreground, 1.9)
readonly property color transparent: "transparent" readonly property color transparent: "transparent"
readonly property double highlightOpacity: .3 readonly property double highlightOpacity: .3

View File

@@ -5,11 +5,16 @@ import QtQuick.Layouts
ColumnLayout ColumnLayout
{ {
required property string label required property string label
/**
* Adds an asterisk after the label, informing the user that this field
* is mandatory.
*/
property bool mandatory: false
spacing: Dimensions.s spacing: Dimensions.s
Label Label
{ {
text: label text: label + (mandatory ? "*" : "")
font: Typography.body font: Typography.body
} }
} }

View File

@@ -0,0 +1,5 @@
import QtQuick
RegularExpressionValidator {
regularExpression: /^\S+.*\S+$/
}

View File

@@ -0,0 +1,5 @@
import QtQuick
RegularExpressionValidator {
regularExpression: /^$|([\+!#$%&\*\\/\=?\^_`\.{|}\~\-\_0-9A-Za-z]{1,185})@([0-9A-Za-z\.\-\_]{1,64})\.([a-zA-z]{2,5})/
}

View File

@@ -0,0 +1,5 @@
import QtQuick
RegularExpressionValidator {
regularExpression: /^$|([+0-9])([0-9\s]{1,17})/
}

View File

@@ -4,6 +4,7 @@ import QtQuick.Templates as T
T.TextField T.TextField
{ {
id: control id: control
background: Rectangle background: Rectangle
{ {
id: background id: background

View File

@@ -10,7 +10,10 @@ Field Field.qml
H1 H1.qml H1 H1.qml
H2 H2.qml H2 H2.qml
Label Label.qml Label Label.qml
NotEmptyValidator NotEmptyValidator.qml
OptionalEmailAddressValidator OptionalEmailAddressValidator.qml
PhoneNumberValidator PhoneNumberValidator.qml PhoneNumberValidator PhoneNumberValidator.qml
OptionalPhoneNumberValidator OptionalPhoneNumberValidator.qml
PostcodeValidator PostcodeValidator.qml PostcodeValidator PostcodeValidator.qml
QuickFilter QuickFilter.qml QuickFilter QuickFilter.qml
SearchBar SearchBar.qml SearchBar SearchBar.qml

View File

@@ -2,7 +2,6 @@ from .DbManager import DbManager
import json import json
import mariadb import mariadb
from PySide6.QtCore import QObject, Signal from PySide6.QtCore import QObject, Signal
# from ..PyqcrmFlags import PyqcrmAppliEmpyFlags
class EmployeeDAO(QObject): class EmployeeDAO(QObject):
@@ -35,7 +34,7 @@ class EmployeeDAO(QObject):
#self.__all_cols = [desc[0] for desc in self.__cur.description] #self.__all_cols = [desc[0] for desc in self.__cur.description]
return self.__cur.fetchall() #, self.__all_cols return self.__cur.fetchall() #, self.__all_cols
else: else:
return None #, None return None
except mariadb.Error as e: except mariadb.Error as e:
print(str(e)) print(str(e))

View File

@@ -1,4 +1,8 @@
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Slot, Signal import json
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Slot, Signal, QJsonDocument
from PySide6.QtQml import QJSValue
from .EmployeeDAO import EmployeeDAO from .EmployeeDAO import EmployeeDAO
# from ..PyqcrmFlags import PyqcrmFlags, PyqcrmAppliEmpyFlags # from ..PyqcrmFlags import PyqcrmFlags, PyqcrmAppliEmpyFlags
from ..ConfigLoader import ConfigLoader from ..ConfigLoader import ConfigLoader
@@ -24,11 +28,27 @@ class EmployeeModel(QAbstractTableModel):
self.__getData() self.__getData()
@Slot(dict, bool) @Slot(dict, bool)
def addEmployee(self, new_employee, applicant = True): def addEmployee(self, new_employee):
if 'worklicense' in new_employee: if 'worklicense' in new_employee:
new_employee['worklicense'] = int(new_employee['worklicense']) new_employee['worklicense'] = int(new_employee['worklicense'])
new_employee['residencetype'] = int(new_employee['residencetype']) new_employee['residencetype'] = int(new_employee['residencetype'])
self.__employee_dao.addEmployee(new_employee, self.__key, applicant) self.__employee_dao.addEmployee(new_employee, self.__key, False)
@Slot(QJSValue)
def addApplicant(self, applicant: QJSValue):
self.__employee_dao.addEmployee({
"city": applicant.property("city").toString(),
"email": applicant.property("email").toString(),
"firstname": applicant.property("firstname").toString(),
"formofaddress": applicant.property("formofaddress").toString(),
"houseno": applicant.property("houseno").toString(),
"lastname": applicant.property("lastname").toString(),
"mobile": applicant.property("mobile").toString(),
"phone": applicant.property("phone").toString(),
"postcode": applicant.property("postcode").toInt(),
"street": applicant.property("street").toString(),
"title": applicant.property("title").toString(),
}, self.__key, True)
@Slot(bool) @Slot(bool)
def __refreshView(self, added): def __refreshView(self, added):
@@ -38,7 +58,8 @@ class EmployeeModel(QAbstractTableModel):
def __getData(self, criterion="Alle", processed=False, fired=False, every_state=True): def __getData(self, criterion="Alle", processed=False, fired=False, every_state=True):
self.beginResetModel() self.beginResetModel()
rows, self.__visible_columns = self.__employee_dao.getEmployees(self.__key, criterion, processed, fired, every_state) rows, self.__visible_columns = self.__employee_dao.getEmployees(self.__key, criterion, processed, fired,
every_state)
self.__data = rows self.__data = rows
self.endResetModel() self.endResetModel()
@@ -58,7 +79,8 @@ class EmployeeModel(QAbstractTableModel):
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
row = self.__data[index.row()] row = self.__data[index.row()]
applicant_col = index.column() + self.__col_skip applicant_col = index.column() + self.__col_skip
tr = row[applicant_col] #if type(row[index.column() + 2]) is str else str(row[index.column() + 2], "utf-8") tr = row[
applicant_col] # if type(row[index.column() + 2]) is str else str(row[index.column() + 2], "utf-8")
if applicant_col == 2 and self.__everyone: if applicant_col == 2 and self.__everyone:
tr = 'Ja' if tr == 1 else 'Nein' tr = 'Ja' if tr == 1 else 'Nein'
else: else:

View File

@@ -1,6 +1,5 @@
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Slot, Signal from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Slot, Signal
from .ObjectDAO import ObjectDAO from .ObjectDAO import ObjectDAO
# from ..PyqcrmFlags import PyqcrmFlags, PyqcrmAppliEmpyFlags
from ..ConfigLoader import ConfigLoader from ..ConfigLoader import ConfigLoader
import re import re
import json import json

View File

@@ -57,7 +57,11 @@
<file>TeroStyle/H1.qml</file> <file>TeroStyle/H1.qml</file>
<file>TeroStyle/H2.qml</file> <file>TeroStyle/H2.qml</file>
<file>TeroStyle/Label.qml</file> <file>TeroStyle/Label.qml</file>
<file>TeroStyle/NotEmptyValidator.qml</file>
<file>TeroStyle/OptionalEmailAddressValidator.qml</file>
<file>TeroStyle/OptionalPhoneNumberValidator.qml</file>
<file>TeroStyle/PhoneNumberValidator.qml</file> <file>TeroStyle/PhoneNumberValidator.qml</file>
<file>TeroStyle/PostcodeValidator.qml</file>
<file>TeroStyle/qmldir</file> <file>TeroStyle/qmldir</file>
<file>TeroStyle/QuickFilter.qml</file> <file>TeroStyle/QuickFilter.qml</file>
<file>TeroStyle/SearchBar.qml</file> <file>TeroStyle/SearchBar.qml</file>