diff --git a/Gui/Employees/AddApplicant.qml b/Gui/Employees/AddApplicant.qml
index 47cad5d..630fa6b 100644
--- a/Gui/Employees/AddApplicant.qml
+++ b/Gui/Employees/AddApplicant.qml
@@ -6,23 +6,38 @@ ColumnLayout {
anchors.fill: parent
spacing: Dimensions.l
+ Component.onCompleted: {
+ employee_model.addedNewEmployee.connect(successful => {
+ if (successful)
+ contentStack.pop();
+ });
+ }
+
ApplicantForm {
+ id: applicantForm
+
Layout.alignment: Qt.AlignTop
Layout.fillHeight: true
Layout.verticalStretchFactor: 1
}
RowLayout {
- spacing: Dimensions.l
Layout.alignment: Qt.AlignRight
+ spacing: Dimensions.l
Button {
icon.source: "qrc:/images/ArrowLeftCircle-Outline.svg"
text: qsTr("Verwerfen")
- }
+ onClicked: contentStack.pop()
+ }
Button {
+ enabled: applicantForm.valid
icon.source: "qrc:/images/CheckCircle.svg"
text: qsTr("Speichern")
+
+ onClicked: {
+ employee_model.addApplicant(applicantForm.value);
+ }
}
}
}
\ No newline at end of file
diff --git a/Gui/Employees/AddEmployee.qml b/Gui/Employees/AddEmployee.qml
index 6d42851..9ce7e0e 100644
--- a/Gui/Employees/AddEmployee.qml
+++ b/Gui/Employees/AddEmployee.qml
@@ -7,12 +7,7 @@ ColumnLayout {
id: colPar
function checkFields() {
- if (radio.children[1].checked) {
- if (!personalData.checkPersonalField())
- saveBtn.enabled = false;
- else
- saveBtn.enabled = true;
- } else if (!personalData.checkPersonalField())
+ if (!personalData.checkPersonalField())
saveBtn.enabled = false;
else
saveBtn.enabled = true;
@@ -49,20 +44,6 @@ ColumnLayout {
personalData.requiredField();
}
}
- Row {
- id: radio
-
- Layout.fillWidth: true
-
- //Layout.columnSpan: 2
- RadioButton {
- checked: true
- text: qsTr("Bewerber")
- }
- RadioButton {
- text: qsTr("Mitarbeiter")
- }
- }
RowLayout {
Layout.fillWidth: true
spacing: 50
@@ -121,22 +102,8 @@ ColumnLayout {
text: qsTr("Speichern")
onClicked: {
- var new_applicant;
- 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);
- // var new_contact = JsLib.addApplicant(addContactLayout)
- // contact_model.addContact(new_contact)
- // console.log(JSON.stringify (new_applicant))
- }
+ const new_applicant = JsLib.parseForm(personalData, bankAccount, nationalInsurance, applicantVarious);
+ employee_model.addEmployee(new_applicant, false);
}
}
}
diff --git a/Gui/Employees/ApplicantForm.qml b/Gui/Employees/ApplicantForm.qml
index d66a815..5a6f0f9 100644
--- a/Gui/Employees/ApplicantForm.qml
+++ b/Gui/Employees/ApplicantForm.qml
@@ -6,6 +6,20 @@ import TeroStyle
ColumnLayout {
readonly property int fieldM: 235
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
@@ -34,31 +48,43 @@ ColumnLayout {
onCurrentTextChanged: {
switch (title.currentIndex) {
case 1:
- salutation.text = "Sehr geehrter Herr ";
+ formofaddress.text = "Sehr geehrter Herr ";
break;
case 2:
- salutation.text = "Sehr geehrte Frau ";
+ formofaddress.text = "Sehr geehrte Frau ";
break;
default:
- salutation.text = "Guten Tag ";
+ formofaddress.text = "Guten Tag ";
}
}
}
}
Field {
- label: qsTr("Vorname*")
+ label: qsTr("Vorname")
+ mandatory: true
TextField {
+ id: firstname
+
implicitWidth: fieldM
- placeholderText: "Max"
+ placeholderText: qsTr("Max")
+
+ validator: NotEmptyValidator {
+ }
}
}
Field {
- label: qsTr("Nachname*")
+ label: qsTr("Nachname")
+ mandatory: true
TextField {
+ id: lastname
+
implicitWidth: fieldM
placeholderText: qsTr("Mustermann")
+
+ validator: NotEmptyValidator {
+ }
}
}
}
@@ -66,6 +92,8 @@ ColumnLayout {
spacing: Dimensions.m
Field {
+ id: street
+
label: qsTr("Straße")
TextField {
@@ -74,6 +102,8 @@ ColumnLayout {
}
}
Field {
+ id: houseno
+
label: qsTr("Hausnummer")
TextField {
@@ -86,6 +116,8 @@ ColumnLayout {
ComboBox {
id: postcode
+
+ currentIndex: -1
editable: true
implicitWidth: fieldS
model: address_model
@@ -97,14 +129,19 @@ ColumnLayout {
}
Field {
label: qsTr("Ort")
+ mandatory: true
ComboBox {
id: city
+ currentIndex: -1
editable: true
implicitWidth: fieldM
model: address_model
textRole: "city"
+
+ validator: NotEmptyValidator {
+ }
}
}
}
@@ -125,10 +162,12 @@ ColumnLayout {
label: qsTr("Telefonnummer")
TextField {
+ id: phone
+
implicitWidth: fieldM
placeholderText: "+49 1234 567890"
- validator: PhoneNumberValidator {
+ validator: OptionalPhoneNumberValidator {
}
}
}
@@ -136,10 +175,12 @@ ColumnLayout {
label: qsTr("Mobil")
TextField {
+ id: mobile
+
implicitWidth: fieldM
placeholderText: "+49 123 4567891011"
- validator: PhoneNumberValidator {
+ validator: OptionalPhoneNumberValidator {
}
}
}
@@ -147,10 +188,12 @@ ColumnLayout {
label: qsTr("E-Mail Adresse")
TextField {
+ id: email
+
implicitWidth: fieldM
placeholderText: "tero@example.org"
- validator: EmailAddressValidator {
+ validator: OptionalEmailAddressValidator {
}
}
}
@@ -158,7 +201,7 @@ ColumnLayout {
label: qsTr("Briefanrede")
TextField {
- id: salutation
+ id: formofaddress
implicitWidth: fieldM
}
diff --git a/TeroStyle/Button.qml b/TeroStyle/Button.qml
index fa4cb19..c0858b4 100644
--- a/TeroStyle/Button.qml
+++ b/TeroStyle/Button.qml
@@ -44,12 +44,12 @@ T.Button {
border.color: Colors.interactive
border.width: isFieldButton ? 1 : 0
bottomLeftRadius: topLeftRadius
- color: !control.hovered ? Colors.primary : Colors.primaryLighter
+ color: !control.enabled ? Colors.disabled : !control.hovered ? Colors.primary : Colors.primaryLighter
radius: Dimensions.radius
topLeftRadius: isFieldButton ? 0 : radius
}
contentItem: I.IconLabel {
- color: Colors.primaryContrast
+ color: !control.enabled ? Colors.disabledForeground : Colors.primaryContrast
display: control.display
font: control.font
icon: control.icon
diff --git a/TeroStyle/Colors.qml b/TeroStyle/Colors.qml
index af7cb98..6331749 100644
--- a/TeroStyle/Colors.qml
+++ b/TeroStyle/Colors.qml
@@ -17,6 +17,8 @@ QtObject {
readonly property color mantle: theme === dark ? "#1E1E23" : "#e7e9ef"
readonly property color interactive: theme === dark ? "#878b97" : "#d9d9da"
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 double highlightOpacity: .3
diff --git a/TeroStyle/Field.qml b/TeroStyle/Field.qml
index e0696fb..85647fd 100644
--- a/TeroStyle/Field.qml
+++ b/TeroStyle/Field.qml
@@ -5,11 +5,16 @@ import QtQuick.Layouts
ColumnLayout
{
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
Label
{
- text: label
+ text: label + (mandatory ? "*" : "")
font: Typography.body
}
}
diff --git a/TeroStyle/NotEmptyValidator.qml b/TeroStyle/NotEmptyValidator.qml
new file mode 100644
index 0000000..c7fb80a
--- /dev/null
+++ b/TeroStyle/NotEmptyValidator.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+RegularExpressionValidator {
+ regularExpression: /^\S+.*\S+$/
+}
diff --git a/TeroStyle/OptionalEmailAddressValidator.qml b/TeroStyle/OptionalEmailAddressValidator.qml
new file mode 100644
index 0000000..4543008
--- /dev/null
+++ b/TeroStyle/OptionalEmailAddressValidator.qml
@@ -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})/
+}
diff --git a/TeroStyle/OptionalPhoneNumberValidator.qml b/TeroStyle/OptionalPhoneNumberValidator.qml
new file mode 100644
index 0000000..24ff8b2
--- /dev/null
+++ b/TeroStyle/OptionalPhoneNumberValidator.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+RegularExpressionValidator {
+ regularExpression: /^$|([+0-9])([0-9\s]{1,17})/
+}
diff --git a/TeroStyle/TextField.qml b/TeroStyle/TextField.qml
index 90e9229..94c4e94 100644
--- a/TeroStyle/TextField.qml
+++ b/TeroStyle/TextField.qml
@@ -4,6 +4,7 @@ import QtQuick.Templates as T
T.TextField
{
id: control
+
background: Rectangle
{
id: background
diff --git a/TeroStyle/qmldir b/TeroStyle/qmldir
index b461990..fa71985 100644
--- a/TeroStyle/qmldir
+++ b/TeroStyle/qmldir
@@ -10,7 +10,10 @@ Field Field.qml
H1 H1.qml
H2 H2.qml
Label Label.qml
+NotEmptyValidator NotEmptyValidator.qml
+OptionalEmailAddressValidator OptionalEmailAddressValidator.qml
PhoneNumberValidator PhoneNumberValidator.qml
+OptionalPhoneNumberValidator OptionalPhoneNumberValidator.qml
PostcodeValidator PostcodeValidator.qml
QuickFilter QuickFilter.qml
SearchBar SearchBar.qml
diff --git a/lib/DB/EmployeeDAO.py b/lib/DB/EmployeeDAO.py
index 5c0cb0c..b3ad69f 100644
--- a/lib/DB/EmployeeDAO.py
+++ b/lib/DB/EmployeeDAO.py
@@ -2,7 +2,6 @@ from .DbManager import DbManager
import json
import mariadb
from PySide6.QtCore import QObject, Signal
-# from ..PyqcrmFlags import PyqcrmAppliEmpyFlags
class EmployeeDAO(QObject):
@@ -35,7 +34,7 @@ class EmployeeDAO(QObject):
#self.__all_cols = [desc[0] for desc in self.__cur.description]
return self.__cur.fetchall() #, self.__all_cols
else:
- return None #, None
+ return None
except mariadb.Error as e:
print(str(e))
diff --git a/lib/DB/EmployeeModel.py b/lib/DB/EmployeeModel.py
index 8876603..e5357aa 100644
--- a/lib/DB/EmployeeModel.py
+++ b/lib/DB/EmployeeModel.py
@@ -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 ..PyqcrmFlags import PyqcrmFlags, PyqcrmAppliEmpyFlags
from ..ConfigLoader import ConfigLoader
@@ -24,11 +28,27 @@ class EmployeeModel(QAbstractTableModel):
self.__getData()
@Slot(dict, bool)
- def addEmployee(self, new_employee, applicant = True):
+ def addEmployee(self, new_employee):
if 'worklicense' in new_employee:
new_employee['worklicense'] = int(new_employee['worklicense'])
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)
def __refreshView(self, added):
@@ -36,16 +56,17 @@ class EmployeeModel(QAbstractTableModel):
self.__getData()
self.addedNewEmployee.emit(added)
- 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()
- 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.endResetModel()
- def rowCount(self, parent= QModelIndex()):
- return len (self.__data)
+ def rowCount(self, parent=QModelIndex()):
+ return len(self.__data)
- def columnCount(self, parent= QModelIndex()):
+ def columnCount(self, parent=QModelIndex()):
return len(self.__visible_columns) - self.__col_skip
@Slot(str)
@@ -54,22 +75,23 @@ class EmployeeModel(QAbstractTableModel):
self.__col_skip = 2
self.__getData(criterion, criterion == 'Erledigt', False, criterion == 'Alle')
- def data(self, index, role= Qt.DisplayRole):
+ def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
row = self.__data[index.row()]
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:
tr = 'Ja' if tr == 1 else 'Nein'
else:
if tr:
- tr = re.sub("Keine Angabe ","", tr)
- #print(f"Data: {tr}")
+ tr = re.sub("Keine Angabe ", "", tr)
+ # print(f"Data: {tr}")
# return row[index.column() + 2]
return tr
return None
- def headerData(self, section, orientation, role = Qt.DisplayRole):
+ def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
self.__col_name = self.__visible_columns[section + self.__col_skip]
return self.__col_name
@@ -77,11 +99,11 @@ class EmployeeModel(QAbstractTableModel):
@Slot(int)
def onRowClicked(self, row):
- #print(self.__data)
+ # print(self.__data)
print(f"Selected table row: {row}, corresponding DB ID: {self.__data[row][0]}")
- #if not self.__employee_dict['employee'] or self.__data[row][0] != self.__employee_dict['employee']['id']:
- #self.__employee = self.__employee_dao.getEmployee(self.__data[row][0], self.__key)
- #print(self.__business)
- #self.__getEmployeeInfo()
- # self.__getContactInfo()
- # print(self.__business_dict)
+ # if not self.__employee_dict['employee'] or self.__data[row][0] != self.__employee_dict['employee']['id']:
+ # self.__employee = self.__employee_dao.getEmployee(self.__data[row][0], self.__key)
+ # print(self.__business)
+ # self.__getEmployeeInfo()
+ # self.__getContactInfo()
+ # print(self.__business_dict)
diff --git a/lib/DB/ObjectModel.py b/lib/DB/ObjectModel.py
index ba19df5..34b2d08 100644
--- a/lib/DB/ObjectModel.py
+++ b/lib/DB/ObjectModel.py
@@ -1,6 +1,5 @@
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Slot, Signal
from .ObjectDAO import ObjectDAO
-# from ..PyqcrmFlags import PyqcrmFlags, PyqcrmAppliEmpyFlags
from ..ConfigLoader import ConfigLoader
import re
import json
diff --git a/qml.qrc b/qml.qrc
index 55a4029..9d1b12c 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -57,7 +57,11 @@
TeroStyle/H1.qml
TeroStyle/H2.qml
TeroStyle/Label.qml
+ TeroStyle/NotEmptyValidator.qml
+ TeroStyle/OptionalEmailAddressValidator.qml
+ TeroStyle/OptionalPhoneNumberValidator.qml
TeroStyle/PhoneNumberValidator.qml
+ TeroStyle/PostcodeValidator.qml
TeroStyle/qmldir
TeroStyle/QuickFilter.qml
TeroStyle/SearchBar.qml