Compare commits

..

21 Commits

Author SHA256 Message Date
fdaae34678 Änderungen letzt Woche 2025-02-24 09:28:40 +01:00
b468c3d078 Adjusted display of applicant/employee and optimised the DB 2025-02-14 17:50:11 +01:00
5ff4749247 Employee/Applicant GUI and DB 2025-02-14 12:05:45 +01:00
80bd2c9be2 Employee and applicant frontend and backend 2025-02-13 09:11:26 +01:00
bfd1d0974d Fummeljob hierum darum 2025-02-12 09:01:38 +01:00
b162117a80 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-02-04 10:50:33 +01:00
3eeb6ab910 TopBar modified to style buttons 2025-02-04 10:49:14 +01:00
aca38067d0 DOC änderung 2025-02-04 10:45:25 +01:00
1f5e9c01e8 Email regex updated for employee and customers 2025-02-04 10:16:30 +01:00
42c7a9c33a Regular expression email in kunden 2025-02-04 10:06:03 +01:00
0813c3c8c0 Merge branch 'refs/heads/linuxero' 2025-02-04 09:43:25 +01:00
bcc616d3b5 Stale GUI deleted and menu buttons very attractive and sexy 2025-02-04 09:41:17 +01:00
f710db48de backup encryption file 2025-02-03 16:46:57 +01:00
a709aa6da1 not needed 2025-02-03 16:24:31 +01:00
83d44cf3c7 copied 2025-02-03 16:23:54 +01:00
b5c3b56fb3 copied 2025-02-03 16:23:43 +01:00
931a99c06b copied 2025-02-03 16:23:31 +01:00
337f383701 copied 2025-02-03 16:23:19 +01:00
af04b3baa1 Andre 2025-02-03 16:04:06 +01:00
0b55556fb4 Für Andre 2025-02-03 15:51:53 +01:00
0923365cbd Add Applicant form changed 2025-02-03 08:41:07 +01:00
56 changed files with 24615 additions and 894 deletions

View File

@@ -8,6 +8,9 @@ ColumnLayout
{ {
id: colPar id: colPar
anchors.fill: parent anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
implicitWidth: parent.width
Label Label
{ {
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
@@ -29,7 +32,7 @@ ColumnLayout
{ {
Layout.fillWidth: true Layout.fillWidth: true
id: radio id: radio
Layout.columnSpan: 2 //Layout.columnSpan: 2
RadioButton RadioButton
{ {
checked: true checked: true
@@ -40,15 +43,30 @@ ColumnLayout
text: qsTr("Mitarbeiter") text: qsTr("Mitarbeiter")
} }
} }
// ScrollView
// {
// Layout.fillHeight: true
// Layout.fillWidth: true
// implicitWidth: parent.width
// ColumnLayout
// {
// anchors.fill: parent
// //implicitWidth: parent.width
// //width: parent.width
// //height: parent.height
RowLayout RowLayout
{ {
Layout.fillWidth: true Layout.fillWidth: true
//implicitWidth: parent.width
spacing: 50 spacing: 50
Frame Frame
{ {
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.fillWidth: true Layout.fillWidth: true
//implicitWidth: parent.width
ApplicantPersonalData ApplicantPersonalData
{ {
id: personalData id: personalData
@@ -64,7 +82,7 @@ ColumnLayout
ColumnLayout ColumnLayout
{ {
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
width: parent.width implicitWidth: parent.width
ApplicantBankData ApplicantBankData
{ {
@@ -84,9 +102,14 @@ ColumnLayout
} }
} }
RowLayout Item
{ {
Layout.fillHeight: true Layout.fillHeight: true
}
RowLayout
{
Layout.fillWidth: true
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
Button Button
{ {
@@ -103,26 +126,28 @@ ColumnLayout
var new_applicant var new_applicant
if (radio.children[0].checked) if (radio.children[0].checked)
{ {
// Ein Bewerber
new_applicant = JsLib.parseForm(personalData) new_applicant = JsLib.parseForm(personalData)
// business_model.addApplicant(new_business, 0) employee_model.addEmployee(new_applicant, true)
// appLoader.source = "EmployeeTable.qml" // appLoader.source = "EmployeeTable.qml"
console.log(JSON.stringify (new_applicant)) // console.log(JSON.stringify (new_applicant))
} }
else else
{ {
// Ein Mitarbeiter
// console.log(personalData, bankAccount, nationalInsurance, applicantVarious) // console.log(personalData, bankAccount, nationalInsurance, applicantVarious)
new_applicant = JsLib.parseForm(personalData, bankAccount, nationalInsurance, applicantVarious) new_applicant = JsLib.parseForm(personalData, bankAccount, nationalInsurance, applicantVarious)
employee_model.addEmployee(new_applicant, false)
// var new_contact = JsLib.addApplicant(addContactLayout) // var new_contact = JsLib.addApplicant(addContactLayout)
// contact_model.addContact(new_contact) // contact_model.addContact(new_contact)
console.log(JSON.stringify (new_applicant)) // console.log(JSON.stringify (new_applicant))
} }
} }
} }
} }
Item // }
{ // } // ScrollView
Layout.fillHeight: true
}
function checkFields() function checkFields()
{ {
if(radio.children[1].checked) if(radio.children[1].checked)

View File

@@ -83,7 +83,7 @@ Frame
placeholderText: qsTr("beispiel@domain.de") placeholderText: qsTr("beispiel@domain.de")
validator: RegularExpressionValidator validator: RegularExpressionValidator
{ {
regularExpression: /([\+!#$%&\*\\/\=?\^_`\.{|}\~0-9A-Za-z]{1,185})@([0-9A-Za-z\.]{1,64})\.([a-zA-z]{2,5})/ regularExpression: /([\+!#$%&\*\\/\=?\^_`\.{|}\~\-\_0-9A-Za-z]{1,185})@([0-9A-Za-z\.\-\_]{1,64})\.([a-zA-z]{2,5})/
} }
} }
@@ -143,9 +143,7 @@ Frame
var bd = birthday.text var bd = birthday.text
if (len === 2 || len === 5) birthday.text = bd + "." if (len === 2 || len === 5) birthday.text = bd + "."
} }
} }
} }
Label Label

252
Gui/AddNewObject.qml Normal file
View File

@@ -0,0 +1,252 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
GridLayout
{
id: newObject
columns: 4
Layout.fillWidth: true
Layout.fillHeight: true
rowSpacing: 9
Label
{
text: qsTr("Firma")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
ComboBox
{
property string name: "business"
id: business
editable: true
Layout.fillWidth: true
Layout.columnSpan: 3
onEditTextChanged: checkFields()
onCurrentTextChanged: checkFields()
}
//// New grid row
Label
{
text: qsTr("Straße")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
TextField
{
property string name: "street"
id: street
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
onTextChanged: checkFields()
placeholderText: "Pflichtfeld"
placeholderTextColor: "red"
}
Label
{
text: qsTr("Nr.")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
TextField
{
property string name: "houseno"
id: houseno
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
onTextChanged: checkFields()
placeholderText: "Pflichtfeld"
placeholderTextColor: "red"
}
// New grid row
Label
{
text: qsTr("PLZ")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
ComboBox
{
property string name: "postcode"
id: postcode
Layout.fillWidth: true
editable: true
onCurrentTextChanged: checkFields()
onEditTextChanged: checkFields()
onActivated: currentValue
model: address_model
textRole: "display"
popup.height: 300
popup.y: postcode.y + 5 - (postcode.height * 2)
currentIndex: -1
onCurrentIndexChanged: city.currentIndex = postcode.currentIndex
validator: RegularExpressionValidator
{
regularExpression: /([0-9]{1,5})/
}
}
Label
{
text: qsTr("Ort")
Layout.alignment: Qt.AlignRight
}
ComboBox
{
property string name: "city"
id: city
Layout.fillWidth: true
editable: true
onEditTextChanged: checkFields()
onCurrentTextChanged: checkFields()
model: address_model
textRole: "city"
popup.height: 300
popup.y: postcode.y + 5 - (postcode.height * 2)
currentIndex: -1
}
// New grid row
Label
{
text: qsTr("Parteien")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
SpinBox
{
property string name: "partitions"
id: partitions
Layout.fillWidth: true
from: 1
to: 100
value: 1
}
Label
{
text: qsTr("Stockwerke")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
SpinBox
{
property string name: "floors"
id: floors
Layout.fillWidth: true
from: 1
to: 100
value: 1
}
// New grid row
Label
{
text: qsTr("Zwischenetage")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
ComboBox
{
property string name: "mezzanin"
id: mezzanin
Layout.fillWidth: true
editable: false
model: [qsTr("Jööö"), qsTr("Nöööööööööööööööööööööööööö")]
}
Label
{
text: qsTr("Aufzug")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
ComboBox
{
property string name: "lift"
id: lift
Layout.fillWidth: true
editable: false
model: [qsTr("Jööö"), qsTr("Nöööööööööööööööööööööööööö")]
}
//New grid row
Label
{
text: qsTr("Besonderheiten")
Layout.alignment: Qt.AlignRight
}
ComboBox
{
property string name: "remarks"
id: remarks
Layout.fillWidth: true
editable: false
textRole: "display"
}
//// New grid row
Label
{
text: qsTr("Kontaktdaten")
Layout.alignment: Qt.AlignRight | Qt.AlignTop
}
ComboBox
{
property string name: "contact"
id: contact
Layout.fillWidth: true
editable: false
model: [qsTr("Beirat"), qsTr("Hausmeister")]
}
Label
{
text: qsTr("Reinigungsmittel wo?")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
TextField
{
property string name: "cleansing"
id: cleansing
Layout.fillWidth: true
placeholderText: "Pflichtfeld"
placeholderTextColor: "red"
onTextChanged: checkFields()
}
Item
{
Layout.fillHeight: true
}
function checkObjectField()
{
return ((business.editText.trim() || business.currentText.trim()) &&
street.text.trim() && houseno.text.trim() &&
(postcode.editText.trim() || postcode.currentText.trim()) &&
(city.editText.trim() || city.currentText.trim()) &&
cleansing.text.trim())
}
}

View File

@@ -20,19 +20,19 @@ ColumnLayout
} }
CheckBox CheckBox
{ {
id: checkAddObject id: checkAddContact
text: qsTr("Mitarbeiter/Ansprechpartner hinzufügen") text: qsTr("Ansprechpartner hinzufügen")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
checked: false checked: false
onCheckStateChanged: onCheckStateChanged:
{ {
//checkFields() checkFields()
} }
} }
RowLayout RowLayout
{ {
id: addobject id: addObject
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
spacing: 45 spacing: 45
@@ -41,9 +41,9 @@ ColumnLayout
{ {
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.fillWidth: true Layout.fillWidth: true
ObjectView AddNewObject
{ {
id: objectView id: newObject
width: parent.width width: parent.width
} }
} }
@@ -51,7 +51,7 @@ ColumnLayout
ObjectAddOns ObjectAddOns
{ {
id: addObjectLayout id: addObjectLayout
visible: checkAddObject.checked visible: checkAddContact.checked
} }
} }
RowLayout RowLayout
@@ -65,22 +65,25 @@ ColumnLayout
} }
Button Button
{ {
property var new_object: null
id: saveBtn id: saveBtn
text: qsTr("Speichern") text: qsTr("Speichern")
enabled: false enabled: false
onClicked: onClicked:
{ {
if (!checkAddObject.checked) if (!checkAddContact.checked)
{ {
new_object = JsLib.parseForm(objectView) var list = []
object_model.addObject(new_object, 0) new_object = JsLib.parseForm(newObject)
appLoader.source = "ObjectTable.qml" object_model.addObject(new_object, list)
} }
else else
{ {
new_object = JsLib.parseForm(objectView) new_object = JsLib.parseForm(newObject)
var new_objecto = JsLib.parseForm(addObjectLayout) var new_objecto = addObjectLayout.getForm()
objecto_model.addObject(new_objecto) object_model.addObject(new_object, new_objecto)
} }
} }
} }
@@ -105,18 +108,18 @@ ColumnLayout
// } // }
// } // }
// function checkFields() function checkFields()
// { {
// if(checkAddObject.checked) if(checkAddContact.checked)
// { {
// if(!objectView.checkObjectField() || !addObjectLayout.checkObjectField()) if(!newObject.checkObjectField() || !addObjectLayout.contactPerson.contacts || !addObjectLayout.contactPerson.contacts.length)
// saveBtn.enabled = false saveBtn.enabled = false
// else else
// saveBtn.enabled = true saveBtn.enabled = true
// } }
// else if (!objectView.checkObjectField()) else if (!newObject.checkObjectField())
// saveBtn.enabled = false saveBtn.enabled = false
// else else
// saveBtn.enabled = true saveBtn.enabled = true
// } }
} }

View File

@@ -1,52 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Label
{
text: qsTr("Geburtsname")
}
TextField
{
id: birthname
Layout.fillWidth: true
}
Label
{
text: qsTr("Geburtsdatum")
}
TextField
{
id: birthday
Layout.fillWidth: true
placeholderText: qsTr("TT.MM.JJJJ")
validator: RegularExpressionValidator
{
regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/
}
}
Label
{
text: qsTr("Geburtsort")
}
TextField
{
id: placeofbirth
Layout.fillWidth: true
}
Label
{
text: qsTr("Geschlecht")
}
ComboBox
{
id: gender
Layout.fillWidth: true
editable: false
model: [qsTr("Mann"), qsTr("Frau"), qsTr("Divers")]
}

View File

@@ -1,64 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
GridLayout
{
id: contactData
columns: 2
Label
{
text: qsTr("Straße")
Layout.alignment: Qt.AlignRight
}
TextField
{
id: street
Layout.fillWidth: true
}
Label
{
text: qsTr("PLZ")
Layout.alignment: Qt.AlignRight
}
RowLayout
{
ComboBox
{
id: postcode
Layout.fillWidth: true
}
Label
{
text: qsTr("Ort")
}
ComboBox
{
id: city
Layout.fillWidth: true
}
}
Label
{
text: qsTr("Telefonnummer")
Layout.alignment: Qt.AlignRight
}
TextField
{
id: phonenumber
Layout.fillWidth: true
}
Label
{
text: qsTr("E-Mail")
Layout.alignment: Qt.AlignRight
}
TextField
{
id: email
Layout.fillWidth: true
}
}

View File

@@ -1,19 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
GridLayout
{
columns: 2
Label
{
text: qsTr("Knappschaft")
}
TextField
{
id: knappschaft
Layout.fillWidth: true
}
}

View File

@@ -33,7 +33,7 @@ GridLayout
TextField TextField
{ {
property string name: "socialno" property string name: "socialno"
id: socialnumber id: socialno
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -99,8 +99,8 @@ GridLayout
} }
TextField TextField
{ {
property string name: "passno" property string name: "idnumber"
id: passno id: idnumber
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -111,9 +111,22 @@ GridLayout
} }
TextField TextField
{ {
property string name: "passduration" property string name: "idexpiry"
id: passduration id: idexpiry
Layout.fillWidth: true Layout.fillWidth: true
validator: RegularExpressionValidator
{
regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/
}
Keys.onPressed: (event)=>
{
if (event.key !== Qt.Key_Backspace)
{
var len = idexpiry.length
var bd = idexpiry.text
if (len === 2 || len === 5) idexpiry.text = bd + "."
}
}
} }
Label Label
{ {
@@ -122,8 +135,8 @@ GridLayout
} }
TextField TextField
{ {
property string name: "exhibitionlocation" property string name: "idauthority"
id: exhibitionlocation id: idauthority
Layout.fillWidth: true Layout.fillWidth: true
} }
Label Label
@@ -134,9 +147,22 @@ GridLayout
} }
TextField TextField
{ {
property string name: "exhibitdate" property string name: "idissued"
id: exhibitdate id: idissued
Layout.fillWidth: true Layout.fillWidth: true
validator: RegularExpressionValidator
{
regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/
}
Keys.onPressed: (event)=>
{
if (event.key !== Qt.Key_Backspace)
{
var len = idissued.length
var bd = idissued.text
if (len === 2 || len === 5) idissued.text = bd + "."
}
}
} }
CheckBox CheckBox
{ {
@@ -146,62 +172,90 @@ GridLayout
text: qsTr("Arbeitserlaubnis <font color='red'><b>?</b></font>") text: qsTr("Arbeitserlaubnis <font color='red'><b>?</b></font>")
visible: nation.currentText === "Deutschland"? false:true visible: nation.currentText === "Deutschland"? false:true
} }
Item CheckBox
{ {
Layout.fillWidth: true property string name: "residencetype"
id: residencetype
text: qsTr("Aufenthaltstitel")
visible: nation.currentText === "Deutschland"? false:true visible: nation.currentText === "Deutschland"? false:true
} }
Label Label
{ {
text: qsTr("Aufenthaltstitel Nr.") text: qsTr("Aufenthaltstitel Nr.")
visible: nation.currentText === "Deutschland"? false:true visible: residencetype.checked
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
} }
TextField TextField
{ {
property string name: "residenceno" property string name: "residenceno"
id: residenceno id: residenceno
visible: nation.currentText === "Deutschland"? false:true visible: residencetype.checked
Layout.fillWidth: true Layout.fillWidth: true
} }
Label Label
{ {
text: qsTr("Ausgestellt von") text: qsTr("Ausgestellt von")
visible: nation.currentText === "Deutschland"? false:true visible: residencetype.checked
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
} }
TextField TextField
{ {
property string name: "residenceissuedloc" property string name: "residenceauthority"
id: residenceissuedloc id: residenceauthority
visible: nation.currentText === "Deutschland"? false:true visible: residencetype.checked
Layout.fillWidth: true Layout.fillWidth: true
} }
Label Label
{ {
text: qsTr("Ausgestellt am") text: qsTr("Ausgestellt am")
visible: nation.currentText === "Deutschland"? false:true visible: residencetype.checked
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
} }
TextField TextField
{ {
property string name: "residenceissued" property string name: "residenceissued"
id: residenceissued id: residenceissued
visible: nation.currentText === "Deutschland"? false:true visible: residencetype.checked
Layout.fillWidth: true Layout.fillWidth: true
validator: RegularExpressionValidator
{
regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/
}
Keys.onPressed: (event)=>
{
if (event.key !== Qt.Key_Backspace)
{
var len = residenceissued.length
var bd = residenceissued.text
if (len === 2 || len === 5) residenceissued.text = bd + "."
}
}
} }
Label Label
{ {
text: qsTr("Gültig bis") text: qsTr("Gültig bis")
visible: nation.currentText === "Deutschland"? false:true visible: residencetype.checked
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
} }
TextField TextField
{ {
property string name: "residenceexpire" property string name: "residenceexpiry"
id: residenceexpire id: residenceexpiry
visible: nation.currentText === "Deutschland"? false:true visible: residencetype.checked
Layout.fillWidth: true Layout.fillWidth: true
validator: RegularExpressionValidator
{
regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/
}
Keys.onPressed: (event)=>
{
if (event.key !== Qt.Key_Backspace)
{
var len = residenceexpiry.length
var bd = residenceexpiry.text
if (len === 2 || len === 5) residenceexpiry.text = bd + "."
}
}
} }
} }

View File

@@ -1,37 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
CheckBox
{
Layout.columnSpan: 2
text: qsTr("Arbeitserlaubnis")
}
Label
{
text: qsTr("Staatsangehörigkeit")
}
TextField
{
id: nationality
}
Label
{
text: qsTr("Pass gültig bis")
}
TextField
{
id: pass
}
Label
{
text: qsTr("Aufenthaltstitel gültig bis")
}
TextField
{
id: aufenthalt
}

View File

@@ -6,7 +6,6 @@ GridLayout
{ {
id: personalData id: personalData
columns: 4 columns: 4
Label Label
{ {
text: qsTr("Anrede") text: qsTr("Anrede")
@@ -182,10 +181,18 @@ GridLayout
Layout.columnSpan: 3 Layout.columnSpan: 3
visible: radio.children[1].checked visible: radio.children[1].checked
validator: RegularExpressionValidator validator: RegularExpressionValidator
{ {
regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/ regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/
} }
Keys.onPressed: (event)=>
{
if (event.key !== Qt.Key_Backspace)
{
var len = birthday.length
var bd = birthday.text
if (len === 2 || len === 5) birthday.text = bd + "."
}
}
} }
Label Label
@@ -255,9 +262,10 @@ GridLayout
placeholderTextColor: "red" placeholderTextColor: "red"
Layout.columnSpan: 3 Layout.columnSpan: 3
onTextChanged: checkFields() onTextChanged: checkFields()
placeholderText: qsTr("beispiel@domain.de")
validator: RegularExpressionValidator validator: RegularExpressionValidator
{ {
regularExpression: /([\+!#$%&\*\\/\=?\^_`\.{|}\~0-9A-Za-z]{1,185})@([0-9A-Za-z\.]{1,64})\.([a-zA-z]{2,5})/ regularExpression: /([\+!#$%&\*\\/\=?\^_`\.{|}\~\-\_0-9A-Za-z]{1,185})@([0-9A-Za-z\.\-\_]{1,64})\.([a-zA-z]{2,5})/
} }
} }
Label Label
@@ -310,14 +318,14 @@ GridLayout
} }
Label Label
{ {
text: qsTr("Arbeitsbeginn") text: qsTr("Vertragsbeginn")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
visible: radio.children[1].checked visible: radio.children[1].checked
} }
TextField TextField
{ {
property string name: "workstart" property string name: "contractstart"
id: workstart id: contractstart
Layout.fillWidth: true Layout.fillWidth: true
visible: radio.children[1].checked visible: radio.children[1].checked
placeholderTextColor: "red" placeholderTextColor: "red"
@@ -327,17 +335,26 @@ GridLayout
{ {
regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/ regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/
} }
Keys.onPressed: (event)=>
{
if (event.key !== Qt.Key_Backspace)
{
var len = contractstart.length
var bd = contractstart.text
if (len === 2 || len === 5) contractstart.text = bd + "."
}
}
} }
Label Label
{ {
text: qsTr("Bei Befristung Ende") text: qsTr("Vertragsende")
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
visible: radio.children[1].checked visible: radio.children[1].checked
} }
TextField TextField
{ {
property string name: "workend" property string name: "contractend"
id: workend id: contractend
Layout.fillWidth: true Layout.fillWidth: true
visible: radio.children[1].checked visible: radio.children[1].checked
placeholderTextColor: "red" placeholderTextColor: "red"
@@ -347,6 +364,15 @@ GridLayout
{ {
regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/ regularExpression: /((^|)(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]))\.((^|)(0[1-9]{1}|1[0-2]{1}))\.((^|)(196[0-9]{1}|19[7-9]{1}[0-9]{1}|20[0-9]{2}))/
} }
Keys.onPressed: (event)=>
{
if (event.key !== Qt.Key_Backspace)
{
var len = contractend.length
var bd = contractend.text
if (len === 2 || len === 5) contractend.text = bd + "."
}
}
} }
Label Label
{ {
@@ -409,7 +435,7 @@ GridLayout
&& (city.editText.trim() || city.currentText.trim()) && (city.editText.trim() || city.currentText.trim())
&& birthday.text.trim() && phonenumber.text.trim() && birthday.text.trim() && phonenumber.text.trim()
&& cellphone.text.trim() && email.text.trim() && jobdescription.text.trim() && cellphone.text.trim() && email.text.trim() && jobdescription.text.trim()
&& workstart.text.trim() && workend.text.trim() && briefAnrede.text.trim()) && contractstart.text.trim() && contractend.text.trim() && briefAnrede.text.trim())
} }
} }
function requiredField() function requiredField()
@@ -420,8 +446,8 @@ GridLayout
cellphone.placeholderText = pf cellphone.placeholderText = pf
email.placeholderText = pf email.placeholderText = pf
jobdescription.placeholderText = pf jobdescription.placeholderText = pf
workstart.placeholderText = pf contractstart.placeholderText = pf
workend.placeholderText = pf contractend.placeholderText = pf
briefAnrede.placeholderText = pf briefAnrede.placeholderText = pf
houseno.placeholderText = pf houseno.placeholderText = pf
} }

View File

@@ -16,8 +16,8 @@ GridLayout
TextField TextField
{ {
property string name: "behinderung" property string name: "disability"
id: behinderung id: disability
placeholderText: "0,0" placeholderText: "0,0"
} }
@@ -42,8 +42,8 @@ GridLayout
TextField TextField
{ {
property string name: "kostenstelle" property string name: "office"
id: kostenstelle id: office
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -55,8 +55,8 @@ GridLayout
TextField TextField
{ {
property string name: "fremdlohn" property string name: "empreference"
id: fremdLohnNummer id: empreference
Layout.fillWidth: true Layout.fillWidth: true
} }
} }

View File

@@ -0,0 +1,174 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
GridLayout
{
columns: 2
rowSpacing: 25
Layout.leftMargin: 7
// Grid row
ColumnLayout
{
Layout.columnSpan: 2
Label
{
id: contactLabel
color: "darksalmon"
font.bold: true
text: qsTr("Ansprechpartner")
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['salute'] + " " + contact['contact']['fname'] + " " + contact['contact']['lname']: ""
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Geburtsdatum")
font.bold: true
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['birthday']: ""
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("E-Mail")
font.bold: true
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['email']: ""
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Position")
font.bold: true
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['position']: ""
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Priorität")
font.bold: true
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['priority']: ""
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Telefon")
font.bold: true
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['phone']: ""
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Handy")
font.bold: true
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['cell']: ""
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Abrechnung")
font.bold: true
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['invoice']: ""
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Mahnung")
font.bold: true
}
Label
{
color: "goldenrod"
text: contact? contact['contact']['reminder']: ""
}
}
// Grid row
Item
{
Layout.columnSpan: 2
Layout.fillHeight: true
}
Component.onCompleted:
{
if (contact && contact['contact']['salute'] === "Frau")
contactLabel.text = qsTr("Ansprechpartnerin")
}
}

View File

@@ -2,26 +2,61 @@ import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
Item ColumnLayout
{ {
property int selectedClient: -1 property int selectedClient: -1
property var client: null
property var contact: null
id: clDet id: clDet
ColumnLayout
Button
{ {
Label text: qsTr("Zurück")
//Layout.columnSpan: 2
onClicked: customersStack.pop()
}
SplitView
{
id: clDetView
Layout.fillHeight: true
Layout.fillWidth: true
leftPadding: 9
rightPadding: 9
CustomerDetailsView
{ {
text: qsTr("Ausgewählter Kunde " + selectedClient) id: customerDetails
} }
Button CustomerContactDetails
{ {
text: qsTr("Kunden zeigen") id: contactDetails
onClicked: customersStack.pop() visible: false
} }
NoCustomerContact
{
id: noCustomerContact
visible: false
}
}
Item
{
//Layout.columnSpan: 2
Layout.fillHeight: true
} }
Component.onCompleted: Component.onCompleted:
{ {
business_model.onRowClicked(selectedClient) //business_model.onRowClicked(selectedClient)
client = business_model.getClientDetails()
if (client['business']['contactid'] > 0)
{
contact = contact_model.getContactDetails(client['business']['contactid'])
contactDetails.visible = true
}
else noCustomerContact.visible = true
} }
} }

225
Gui/CustomerDetailsView.qml Normal file
View File

@@ -0,0 +1,225 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
GridLayout
{
columns: 2
rowSpacing: 25
SplitView.preferredWidth: clDetView.width / 3 * 1.8
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Steuer-ID")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['tax']? client['business']['tax']: ""
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Anmerkungen")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['info']? client['business']['info']: ""
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Kundenname")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['company']
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("CEO")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['ceo']
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Telefon")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['phone']? client['business']['phone']: ""
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Handy")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['cell']? client['business']['cell']: ""
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Webseite")
font.bold: true
}
Label
{
id: clientWebsite
color: "goldenrod"
font.underline: false
text: client['business']['website']? '<a href="' + client['business']['website'] + '">' + client['business']['website'] + '</a>': ""
onLinkActivated:
{
var web_protocol = /^((http|https):\/\/)/;
var client_website = !web_protocol.test(client['business']['website'])? "https://" + client['business']['website']: client['business']['website'];
Qt.openUrlExternally(client_website)
}
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("E-Mail")
font.bold: true
}
Label
{
id: clientEmail
color: "goldenrod"
text: client['business']['email']? '<a href="mailto:' + client['business']['email'] + '">' + client['business']['email'] + '</a>': ""
onLinkActivated: Qt.openUrlExternally('mailto:' + client['business']['email'])
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Straße")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['street']? client['business']['tax']: ""
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Haus-Nr.")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['house']? client['business']['house']: ""
}
}
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("PLZ")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['zip']? client['business']['zip']: ""
}
}
ColumnLayout
{
Label
{
color: "darksalmon"
text: qsTr("Stadt")
font.bold: true
}
Label
{
color: "goldenrod"
text: client['business']['city']? client['business']['city']: ""
}
}
// Grid row
// Item
// {
// Layout.columnSpan: 2
// Layout.fillHeight: true
// }
}

View File

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

View File

@@ -22,7 +22,6 @@ Item
onClicked: appLoader.source = "AddCustomer.qml" onClicked: appLoader.source = "AddCustomer.qml"
} }
ColumnLayout ColumnLayout
{ {
id: tableColumn id: tableColumn
@@ -67,7 +66,6 @@ Item
text: qsTr("Erledigt") text: qsTr("Erledigt")
onClicked: viewCriterion(showFinished) onClicked: viewCriterion(showFinished)
} }
} }
HorizontalHeaderView HorizontalHeaderView
@@ -77,78 +75,48 @@ Item
implicitHeight: 40 implicitHeight: 40
movableColumns: true //@disable-check M16 movableColumns: true //@disable-check M16
syncView: customerTable syncView: customerTable
delegate: Rectangle
delegate: Rectangle { {
color: addBusinessBtn.palette.alternateBase color: addBusinessBtn.palette.alternateBase
border.color: addBusinessBtn.palette.base border.color: addBusinessBtn.palette.base
implicitHeight: 40 implicitHeight: 40
Layout.fillWidth: true Layout.fillWidth: true
implicitWidth: 1 implicitWidth: 1
Text Text
{ {
text: model.display text: model.display
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width width: parent.width
height: parent.height height: parent.height
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
color: addBusinessBtn.palette.text color: addBusinessBtn.palette.text
} }
} }
} }
TableView TableView
{ {
//property var customWidths: [0.2, 0.5, 0.3, 05, 0.2, 0.2]
property real newWidth: 0 property real newWidth: 0
id: customerTable id: customerTable
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
ScrollBar.vertical: ScrollBar
{
policy: customerTable.contentHeight > customerTable.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
}
columnSpacing: 1 columnSpacing: 1
rowSpacing: 2 rowSpacing: 2
model: business_model model: business_model
alternatingRows: true alternatingRows: true
resizableColumns: true // @disable-check M16 resizableColumns: true
selectionBehavior: TableView.SelectRows selectionBehavior: TableView.SelectRows
ScrollBar.vertical: ScrollBar
{
policy: customerTable.contentHeight > customerTable.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
}
selectionModel: ItemSelectionModel selectionModel: ItemSelectionModel
{ {
id: selModel id: selModel
model: customerTable.model model: customerTable.model
} }
// columnWidthProvider: function(column)
// {
// switch (column)
// {
// case 0: return width * 0.2;
// case 1: return width * 0.5;
// case 2: return width * 0.3;
// default: return width / model.columnCount();
// }
//return customWidths[column] * width;
//return tableColumn.content.implicitWidth // model.columnCount()
// newWidth = columnWidth(column)
// return newWidth
// }
Timer
{
id: redrawTable
running: true
interval: 1
repeat: false
onTriggered:
{
customerTable.forceLayout();
}
}
delegate:Rectangle delegate:Rectangle
{ {
required property bool selected required property bool selected
@@ -160,32 +128,25 @@ Item
: (customerTable.alternatingRows && row % 2 !== 0 : (customerTable.alternatingRows && row % 2 !== 0
? addBusinessBtn.palette.base // palette.base ? addBusinessBtn.palette.base // palette.base
: addBusinessBtn.palette.alternateBase) //palette.alternateBase) : addBusinessBtn.palette.alternateBase) //palette.alternateBase)
Text Text
{ {
text: model.display == null? "": model.display text: model.display == null? "": model.display // @disable-check M126
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width width: parent.width
height: parent.height height: parent.height
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
leftPadding: 9 //@d isable-check M16 leftPadding: 9
color: addBusinessBtn.palette.text color: addBusinessBtn.palette.text
} }
MouseArea MouseArea
{ {
property bool hovered: false property bool hovered: false
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
// onClicked:
// {
// business_model.onRowClicked(row)
// }
onDoubleClicked: onDoubleClicked:
{ {
business_model.onRowClicked(row)
customersStack.push("CustomerDetails.qml", {selectedClient: row}); customersStack.push("CustomerDetails.qml", {selectedClient: row});
} }
@@ -195,17 +156,10 @@ Item
} }
} }
} }
onContentWidthChanged:
{
//console.log("Model changed!!")
redrawTable.start()
}
} }
Item Item
{ {
//Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
} }
} }

View File

@@ -22,6 +22,6 @@ Item
Component.onCompleted: Component.onCompleted:
{ {
business_model.onRowClicked(selectedEmployee) employee_model.onRowClicked(selectedEmployee)
} }
} }

View File

@@ -23,6 +23,16 @@ Item
onClicked: appLoader.source = "AddApplicant.qml" onClicked: appLoader.source = "AddApplicant.qml"
} }
ButtonGroup
{
id: criterion
// buttons: criterion.children
onClicked:
{
viewEmployees(criterion.checkedButton.text)
}
}
ColumnLayout ColumnLayout
{ {
anchors anchors
@@ -32,79 +42,146 @@ Item
bottom: parent.bottom bottom: parent.bottom
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
RowLayout RowLayout
{ {
//id: criterion
RadioButton RadioButton
{ {
//id: showAll
checked: true checked: true
text: qsTr("Alle") text: qsTr("Alle")
ButtonGroup.group: criterion
//onClicked: viewEmployees(showAll)
} }
RadioButton RadioButton
{ {
//id: showApplicant
text: qsTr("Bewerber") text: qsTr("Bewerber")
ButtonGroup.group: criterion
//onClicked: viewEmployees(showApplicant)
} }
RadioButton RadioButton
{ {
//id: showEmployee
text: qsTr("Mitarbeiter") text: qsTr("Mitarbeiter")
ButtonGroup.group: criterion
//onClicked: viewEmployees(showEmployee)
} }
RadioButton
{
CheckBox
{
id: showEveryone
text: qsTr("Alle Stati")
checked: true
onClicked: viewEmployees(criterion.checkedButton.text)
onCheckedChanged:
{
showFired.checked = false
showProcessed.checked = false
}
}
CheckBox
{
id: showProcessed
text: qsTr("Erledigt") text: qsTr("Erledigt")
enabled: !showEveryone.checked
checked: false
onClicked:
{
showFired.checked = false
viewEmployees(criterion.checkedButton.text)
}
} }
RadioButton CheckBox
{ {
id: showFired
text: qsTr("Ausgeschieden") text: qsTr("Ausgeschieden")
enabled: !showEveryone.checked
checked: false
onClicked:
{
showProcessed.checked = false
viewEmployees(criterion.checkedButton.text)
}
} }
} }
HorizontalHeaderView HorizontalHeaderView
{ {
id: horizontalHeader id: employeeTableHeader
Layout.fillWidth: true Layout.fillWidth: true
syncView: testTable syncView: appliEmpTable
implicitHeight: 40
movableColumns: true //@disable-check M16
delegate: Rectangle
{
color: addEmployeeBtn.palette.alternateBase
border.color: palette.base
implicitHeight: 40
Layout.fillWidth: true
implicitWidth: 1
Text
{
text: model.display
elide: Text.ElideRight
width: parent.width
height: parent.height
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: palette.text
}
}
} }
TableView TableView
{ {
id: testTable id: appliEmpTable
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
columnSpacing: 1 columnSpacing: 1
rowSpacing: 2 rowSpacing: 2
model: business_model alternatingRows: true
resizableColumns: true
model: employee_model
selectionBehavior: TableView.SelectRows selectionBehavior: TableView.SelectRows
ScrollBar.vertical: ScrollBar
{
policy: appliEmpTable.contentHeight > appliEmpTable.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
}
selectionModel: ItemSelectionModel selectionModel: ItemSelectionModel
{
id: selModel
{ model: appliEmpTable.model
id: selModel }
model: testTable.model
}
delegate:Rectangle delegate:Rectangle
{ {
required property bool selected required property bool selected
required property bool current required property bool current
implicitWidth: 200 implicitWidth: appliEmpTable.width / appliEmpTable.columns
implicitHeight: 25 implicitHeight: 25
color: selected? "lightblue": palette.base color: selected
? addEmployeeBtn.palette.highlight //palette.highlight
: (appliEmpTable.alternatingRows && row % 2 !== 0
? addEmployeeBtn.palette.base // palette.base
: addEmployeeBtn.palette.alternateBase) //palette.alternateBase)
Text Text
{ {
Layout.fillWidth: true text: model.display === null? "": model.display
text: model.display? model.display: "" elide: Text.ElideRight
width: parent.width
height: parent.height
verticalAlignment: Text.AlignVCenter
leftPadding: 9 //@d isable-check M16
color: palette.text
} }
@@ -116,17 +193,29 @@ Item
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onDoubleClicked: onDoubleClicked:
{ {
employeesStack.push("EmployeeDetails.qml", {selectedEmployee: row}); employeesStack.push("EmployeeDetails.qml", {selectedEmployee: row});
} }
onEntered:
{
appliEmpTable.selectionModel.select(appliEmpTable.model.index(row, 0), ItemSelectionModel.SelectCurrent | ItemSelectionModel.Rows)
}
} }
} }
} }
Item
{
Layout.fillWidth: true
}
} }
function viewEmployees(criterion)
{
employee_model.viewCriterion(criterion, showProcessed.checked, showFired.checked, showEveryone.checked)
}
Component.onCompleted: employeesStack.pop() Component.onCompleted: employeesStack.pop()
} }

View File

@@ -83,6 +83,13 @@ Item
placeholderText: qsTr ("Benutzernamen eingeben") placeholderText: qsTr ("Benutzernamen eingeben")
implicitWidth: 300 implicitWidth: 300
font: hussarPrint.font font: hussarPrint.font
focus: true
onAccepted:
{
if (benutzerName.text.trim() && passwort.text.trim())
loggedin_user.login(benutzerName.text.trim(), passwort.text)
else if(benutzerName.text.trim()) passwort.forceActiveFocus()
}
} }
} }
@@ -110,6 +117,12 @@ Item
implicitWidth: 300 implicitWidth: 300
font: hussarPrint.font font: hussarPrint.font
echoMode: TextInput.Password echoMode: TextInput.Password
onAccepted:
{
if (benutzerName.text.trim() && passwort.text.trim())
loggedin_user.login(benutzerName.text.trim(), passwort.text)
else if(passwort.text.trim()) benutzerName.forceActiveFocus()
}
} }
} }
@@ -193,6 +206,7 @@ Item
config.invalidEncryptionKey.connect(getEncryptionKey) config.invalidEncryptionKey.connect(getEncryptionKey)
config.checkEncryptionKey() config.checkEncryptionKey()
loggedin_user.noDbConnection.connect(dbConnectionFailed) loggedin_user.noDbConnection.connect(dbConnectionFailed)
benutzerName.forceActiveFocus()
} }
function loggedin() function loggedin()

33
Gui/NoCustomerContact.qml Normal file
View File

@@ -0,0 +1,33 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
GridLayout
{
columns: 2
rowSpacing: 25
// Grid row
ColumnLayout
{
Label
{
color: "darksalmon"
font.bold: true
text: qsTr("Kein Ansprechpartner gefunden")
}
Label
{
color: "goldenrod"
text: qsTr("Was willst du tun?")
}
}
// Grid row
Item
{
Layout.columnSpan: 2
Layout.fillHeight: true
}
}

View File

@@ -7,12 +7,6 @@ GridLayout
property var contacts: null property var contacts: null
columns: 2 columns: 2
CheckBox
{
id: contactperson
text: qsTr("Ansprechpartner")
Layout.columnSpan: 2
}
Label Label
{ {
text: qsTr("Anrede") text: qsTr("Anrede")
@@ -21,9 +15,8 @@ GridLayout
ComboBox ComboBox
{ {
id: title id: title
model: [qsTr("Herr"),qsTr("Frau")] model: [qsTr("Herr"), qsTr("Frau"), qsTr("keine Angabe")]
Layout.fillWidth: true Layout.fillWidth: true
enabled: contactperson.checked
} }
Label Label
{ {
@@ -36,7 +29,7 @@ GridLayout
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: "Pflichtfeld" placeholderText: "Pflichtfeld"
placeholderTextColor: "red" placeholderTextColor: "red"
enabled: contactperson.checked // onTextChanged: checkContactFields()
} }
Label Label
{ {
@@ -49,7 +42,6 @@ GridLayout
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: "Pflichtfeld" placeholderText: "Pflichtfeld"
placeholderTextColor: "red" placeholderTextColor: "red"
enabled: contactperson.checked
} }
Label Label
{ {
@@ -60,9 +52,26 @@ GridLayout
{ {
id: phonenumber id: phonenumber
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: "Pflichtfeld" placeholderText: mobile.text ? "" : "Pflichtfeld"
placeholderTextColor: "red" placeholderTextColor: "red"
enabled: contactperson.checked
}
Label
{
text: qsTr("Mobil")
Layout.alignment: Qt.AlignRight
}
TextField
{
id: mobile
Layout.fillWidth: true
placeholderText: phonenumber.text ? "" : "Pflichtfeld"
placeholderTextColor: "red"
} }
Label Label
{ {
@@ -75,7 +84,6 @@ GridLayout
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: "Pflichtfeld" placeholderText: "Pflichtfeld"
placeholderTextColor: "red" placeholderTextColor: "red"
enabled: contactperson.checked
} }
RowLayout RowLayout
@@ -92,34 +100,63 @@ GridLayout
{ {
id: removeContact id: removeContact
text: qsTr("Entfernen") text: qsTr("Entfernen")
enabled: contactperson.checked enabled: false
onClicked:
{
if (contactView.highlightFollowsCurrentItem)
{
delete contacts[contactView.currentIndex]
contacts = contacts.filter(elm => elm)
contactModel.remove(contactView.currentIndex)
contactView.highlightFollowsCurrentItem = false
contactView.currentIndex = -1
if (Object.keys(contacts).length === 0)
{
enabled = false
}
checkFields()
}
}
} }
Button Button
{ {
id: addContact id: addContact
text: qsTr("Hinzufügen") text: qsTr("Hinzufügen")
enabled: contactperson.checked enabled: firstname.text.trim() && lastname.text.trim() && (phonenumber.text.trim() || mobile.text.trim()) && posizion.text.trim()
onClicked: onClicked:
{ {
var num_contacts = 0 var num_contacts = 0
if (contacts !== null && contacts !== undefined) num_contacts = Object.keys(contacts).length if (contacts !== null && contacts !== undefined) num_contacts = Object.keys(contacts).length
else contacts = {} else contacts = []
if (num_contacts < 3 && firstname.text.trim() !== "" && lastname.text.trim() !== "" && phonenumber.text.trim() !== "" && posizion.text.trim() !== "") if (num_contacts < 3 && firstname.text.trim() !== "" && lastname.text.trim() !== "" && (phonenumber.text.trim() !== "" || mobile.text.trim() !== "") && posizion.text.trim() !== "")
{ {
contacts[num_contacts] = {} contacts[num_contacts] = {}
contacts[num_contacts]["title"] = title.currentText contacts[num_contacts]["title"] = title.currentText
contacts[num_contacts]["fname"] = firstname.text.trim() contacts[num_contacts]["fname"] = firstname.text.trim()
contacts[num_contacts]["lname"] = lastname.text.trim() contacts[num_contacts]["lname"] = lastname.text.trim()
contacts[num_contacts]["phone"] = phonenumber.text.trim() contacts[num_contacts]["phone"] = phonenumber.text.trim()
contacts[num_contacts]["mobile"] = mobile.text.trim()
contacts[num_contacts]["position"] = posizion.text.trim() contacts[num_contacts]["position"] = posizion.text.trim()
contactModel.append({name: title.currentText + " " + firstname.text.trim() + " " + lastname.text.trim(), phone: phonenumber.text.trim(), mobile: mobile.text.trim(), posizion: posizion.text.trim()})
contactModel.append({name: title.currentText + " " + firstname.text.trim() + " " + lastname.text.trim(), phone: phonenumber.text.trim(), posizion: posizion.text.trim()}) if (checkFields())
{
saveBtn.enabled = true
}
firstname.text = "" firstname.text = ""
lastname.text = "" lastname.text = ""
phonenumber.text = "" phonenumber.text = ""
mobile.text = ""
posizion.text = "" posizion.text = ""
if (Object.keys(contacts).length >= 3)
{
enabled = false
}
removeContact.enabled = true
checkFields()
} }
} }
} }
@@ -148,7 +185,7 @@ GridLayout
width: 175 width: 175
font.bold: true font.bold: true
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
color: "black" color: "white"
} }
Text Text
@@ -158,7 +195,17 @@ GridLayout
width: 100 width: 100
font.bold: true font.bold: true
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
color: "black" color: "white"
}
Text
{
id: cpmobile
text: qsTr("Mobil")
width: 100
font.bold: true
horizontalAlignment: Text.AlignLeft
color: "white"
} }
Text Text
@@ -168,29 +215,43 @@ GridLayout
width: 150 width: 150
font.bold: true font.bold: true
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
color: "black" color: "white"
} }
} }
} }
Rectangle Rectangle
{ {
id: mainRect
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: 100 implicitHeight: 100
color: firstname.palette.base color: firstname.palette.base
border.color: firstname.activeFocus? firstname.palette.highlight: firstname.palette.base border.color: firstname.activeFocus? firstname.palette.highlight: firstname.palette.base
ListView ListView
{ {
id: contactView id: contactView
implicitHeight: parent.height implicitHeight: parent.height
implicitWidth: parent.width
model: contactModel model: contactModel
header: headline header: headline
highlight: Rectangle { color: "grey"}
highlightFollowsCurrentItem: false
onActiveFocusChanged: if(!focus) currentIndex = -1
delegate: Item delegate: Item
{ {
width: parent.width width: contactView.width
height: 15 height: 15
MouseArea
{
anchors.fill: parent
onClicked:
{
contactView.currentIndex = index
contactView.highlightFollowsCurrentItem = true
}
}
Row Row
{ {
@@ -200,18 +261,28 @@ GridLayout
text: model.name text: model.name
width: 175 width: 175
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
color: "white"
} }
Text Text
{ {
text: model.phone text: model.phone
width: 100 width: 100
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
color: "white"
}
Text
{
text: model.mobile
width: 100
horizontalAlignment: Text.AlignLeft
color: "white"
} }
Text Text
{ {
text: model.posizion text: model.posizion
width: 150 width: 150
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
color: "white"
} }
} }
} }

View File

@@ -4,120 +4,120 @@ import QtQuick.Controls
GridLayout GridLayout
{ {
property var employeeForm: null // property var employeeForm: null
property var employees: null // property var employees: null
id: oaoemployee // id: oaoemployee
columns: 2 // columns: 2
rows: 4 // rows: 4
Label // Label
{ // {
text: qsTr("Mitarbeiter") // text: qsTr("Mitarbeiter")
Layout.alignment: Qt.AlignRight | Qt.AlignTop // Layout.alignment: Qt.AlignRight | Qt.AlignTop
} // }
ListModel // ListModel
{ // {
id: employeeModel // id: employeeModel
} // }
Component // Component
{ // {
id: employeesHeader // id: employeesHeader
Row // Row
{ // {
Text // Text
{ // {
id: empName // id: empName
text: qsTr("Mitarbeiter") // text: qsTr("Mitarbeiter")
width: 175 // width: 175
font.bold: true // font.bold: true
horizontalAlignment: Text.AlignLeft // horizontalAlignment: Text.AlignLeft
color: "black" // color: "black"
} // }
} // }
} // }
Rectangle // Rectangle
{ // {
Layout.fillWidth: true // Layout.fillWidth: true
implicitHeight: 75 // implicitHeight: 75
Layout.rowSpan: 2 // Layout.rowSpan: 2
color: mitarbeiterhin.palette.base // color: mitarbeiterhin.palette.base
border.color: mitarbeiterhin.activeFocus? mitarbeiterhin.palette.highlight: mitarbeiterhin.palette.base // border.color: mitarbeiterhin.activeFocus? mitarbeiterhin.palette.highlight: mitarbeiterhin.palette.base
ListView // ListView
{ // {
id: employeesList // id: employeesList
//anchors.fill: parent // //anchors.fill: parent
implicitHeight: parent.height // implicitHeight: parent.height
model: employeeModel // model: employeeModel
header: employeesHeader // header: employeesHeader
delegate: Row // delegate: Row
{ // {
width: 200 // width: 200
height: 15 // height: 15
//padding: 7 // //padding: 7
Text // Text
{ // {
text: model.namens // text: model.namens
} // }
} // }
} // }
} // }
RowLayout // RowLayout
{ // {
Layout.columnSpan: 2 // Layout.columnSpan: 2
Layout.fillWidth: true // Layout.fillWidth: true
Item // Item
{ // {
Layout.fillWidth: true // Layout.fillWidth: true
} // }
Button // Button
{ // {
id: mitarbeiterraus // id: mitarbeiterraus
text: qsTr("Mitarbeiter entfernen") // text: qsTr("Mitarbeiter entfernen")
} // }
Button // Button
{ // {
id: mitarbeiterhin // id: mitarbeiterhin
text: qsTr("Mitarbeiter hinzufügen") // text: qsTr("Mitarbeiter hinzufügen")
onClicked: // onClicked:
{ // {
var nm = Qt.createComponent("AddObjectEmployee.qml") // var nm = Qt.createComponent("AddObjectEmployee.qml")
if (nm.status === Component.Ready) // if (nm.status === Component.Ready)
{ // {
employeeForm = nm.createObject (appWindow, {width: 600, height: 400}) // employeeForm = nm.createObject (appWindow, {width: 600, height: 400})
employeeForm.addNewEmployee.connect(onAddEmployee) // employeeForm.addNewEmployee.connect(onAddEmployee)
employeeForm.show() // employeeForm.show()
} // }
else console.log(nm.errorString()) // else console.log(nm.errorString())
} // }
} // }
} // }
function onAddEmployee(new_employee) // function onAddEmployee(new_employee)
{ // {
var num_employees = 0 // var num_employees = 0
if (employees === null || employees === undefined) employees = {} // if (employees === null || employees === undefined) employees = {}
else num_employees = Object.keys(employees).length; // else num_employees = Object.keys(employees).length;
employees[num_employees] = {} // employees[num_employees] = {}
employees[num_employees]["assignee"] = new_employee["assignee"]; // employees[num_employees]["assignee"] = new_employee["assignee"];
employees[num_employees]["duration"] = new_employee["duration"]; // employees[num_employees]["duration"] = new_employee["duration"];
employees[num_employees]["wage"] = new_employee["wage"]; // employees[num_employees]["wage"] = new_employee["wage"];
employees[num_employees]["cleandays"] = new_employee["cleandays"]; // employees[num_employees]["cleandays"] = new_employee["cleandays"];
employees[num_employees]["tasks"] = new_employee["tasks"]; // employees[num_employees]["tasks"] = new_employee["tasks"];
employees[num_employees]["output"] = new_employee["output"]; // employees[num_employees]["output"] = new_employee["output"];
employeeModel.append({namens: new_employee["assignee"]}); // employeeModel.append({namens: new_employee["assignee"]});
} // }
} }

View File

@@ -1,19 +1,17 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls import QtQuick.Controls
import "../js/qmldict.js" as JsLib
Frame Frame
{ {
property alias contactPerson: oaocontactperson
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.fillWidth: true Layout.fillWidth: true
ColumnLayout ColumnLayout
{ {
id: addObjectLayout id: addObjectLayout
width: parent.width width: parent.width
ObjectAddOnEmployee
{
id: oaoemployee
}
ObjectAddOnContactPerson ObjectAddOnContactPerson
{ {
id: oaocontactperson id: oaocontactperson
@@ -23,4 +21,8 @@ Frame
Layout.fillHeight: true Layout.fillHeight: true
} }
} }
function getForm()
{
return oaocontactperson.contacts
}
} }

View File

@@ -6,47 +6,94 @@ GridLayout
{ {
id: objectView id: objectView
columns: 2 columns: 4
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
rowSpacing: 9 rowSpacing: 9
Label
{
text: qsTr("Firma")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
ComboBox
{
property string name: "business"
id: business
editable: true
Layout.fillWidth: true
Layout.columnSpan: 3
}
Label Label
{ {
text: qsTr("Objektstraße") text: qsTr("Straße")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
} }
TextField TextField
{ {
id: objectName property string name: "street"
id: street
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onTextChanged: checkFields() onTextChanged: checkFields()
placeholderText: "Pflichtfeld" placeholderText: "Pflichtfeld"
placeholderTextColor: "red" placeholderTextColor: "red"
//Layout.maximumWidth: parent.width / 2
} }
Label Label
{ {
text: qsTr("Leistungsort") text: qsTr("Nr.")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
} }
TextField TextField
{ {
id: leistungsortid property string name: "houseno"
id: houseno
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: parent.width / 2 Layout.alignment: Qt.AlignVCenter
onTextChanged: checkFields() onTextChanged: checkFields()
placeholderText: "Pflichtfeld" placeholderText: "Pflichtfeld"
placeholderTextColor: "red" placeholderTextColor: "red"
} }
Label
{
text: qsTr("PLZ")
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
}
TextField
{
property string name: "postcode"
id: postcode
Layout.fillWidth: true
onTextChanged: checkFields()
placeholderText: "Pflichtfeld"
placeholderTextColor: "red"
}
Label
{
text: qsTr("Ort")
Layout.alignment: Qt.AlignRight
}
ComboBox
{
property string name: "city"
id: city
Layout.fillWidth: true
editable: true
onEditTextChanged: checkFields()
onCurrentTextChanged: checkFields()
model: address_model
textRole: "city"
popup.height: 300
popup.y: postcode.y + 5 - (postcode.height * 2)
currentIndex: -1
}
Label Label
{ {
text: qsTr("Lohnanteil inkl. Fahrtkosten") text: qsTr("Lohnanteil inkl. Fahrtkosten")
@@ -57,7 +104,7 @@ GridLayout
{ {
id: lohnanteil id: lohnanteil
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: parent.width / 2 Layout.columnSpan: 3
} }
Label Label
@@ -70,7 +117,7 @@ GridLayout
{ {
id: materialanteil id: materialanteil
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: parent.width / 2 Layout.columnSpan: 3
} }
Label Label
@@ -83,7 +130,7 @@ GridLayout
{ {
id: zusatz1 id: zusatz1
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: parent.width / 2 Layout.columnSpan: 3
} }
Label Label
@@ -96,7 +143,7 @@ GridLayout
{ {
id: zusatz2 id: zusatz2
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: parent.width / 2 Layout.columnSpan: 3
} }
Label Label
@@ -109,7 +156,7 @@ GridLayout
{ {
id: gesamtnetto id: gesamtnetto
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: parent.width / 2 Layout.columnSpan: 3
} }
Label Label
@@ -122,7 +169,7 @@ GridLayout
{ {
id: mwst id: mwst
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: parent.width / 2 Layout.columnSpan: 3
} }
Label Label
@@ -135,7 +182,7 @@ GridLayout
{ {
id: gesamt id: gesamt
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: parent.width / 2 Layout.columnSpan: 3
} }
Label Label
@@ -149,9 +196,8 @@ GridLayout
id: zahlungsziel id: zahlungsziel
Layout.fillWidth: true Layout.fillWidth: true
editable: false editable: false
//model: business_type
textRole: "display" textRole: "display"
//Layout.maximumWidth: parent.width / 2 Layout.columnSpan: 3
} }
@@ -165,6 +211,7 @@ GridLayout
id: infoview id: infoview
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 110 Layout.preferredHeight: 110
Layout.columnSpan: 3
ScrollBar.horizontal: ScrollBar ScrollBar.horizontal: ScrollBar
{ {
policy: ScrollBar.AlwaysOn policy: ScrollBar.AlwaysOn
@@ -180,6 +227,7 @@ GridLayout
{ {
color: objectInfo.palette.base color: objectInfo.palette.base
border.color: objectInfo.activeFocus? objectInfo.palette.highlight: objectInfo.palette.base border.color: objectInfo.activeFocus? objectInfo.palette.highlight: objectInfo.palette.base
width: parent.width
} }
} }
} }

View File

@@ -112,7 +112,7 @@ Item
Text Text
{ {
text: model.display == null? "": model.display text: model.display === null? "": model.display
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width width: parent.width
height: parent.height height: parent.height

134
Gui/PrinterDialog.qml Normal file
View File

@@ -0,0 +1,134 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Window
{
property alias printerDialog: printDialog
property var printers: null
id: printDialog
title: qsTr("PYQCRM - Drucker")
color: palette.base
minimumWidth: 300
maximumWidth: 600
minimumHeight: 150
maximumHeight: 150
ColumnLayout
{
spacing: 9
y: 15
implicitWidth: parent.width
RowLayout
{
Layout.fillWidth: true
Layout.leftMargin: 5
Layout.rightMargin: 5
Label
{
id: printersLabel
Layout.alignment: Qt.AlignRight
text: qsTr("Drucker")
}
ComboBox
{
id: allPrinters
model: printers
Layout.fillWidth: true
}
}
RowLayout
{
Layout.leftMargin: 5
Layout.rightMargin: 5
Layout.fillWidth: true
Label
{
Layout.minimumWidth: printersLabel.width
Layout.alignment: Qt.AlignRight
text: qsTr("Kopie")
}
SpinBox
{
id: copiesSpinBox
from: 1
to: 10
value: 1
}
Item
{
Layout.fillWidth: true
}
}
RowLayout
{
Layout.leftMargin: 5
Layout.rightMargin: 5
Layout.fillWidth: true
CheckBox
{
id: colorPrint
text: qsTr("Farbe")
Layout.minimumWidth: printersLabel.width
}
Item
{
Layout.fillWidth: true
}
}
RowLayout
{
Layout.leftMargin: 5
Layout.rightMargin: 5
Layout.fillWidth: true
Item
{
Layout.fillWidth: true
}
Button
{
id: printButton
text: qsTr("Drucken")
onClicked:
{
var copies = copiesSpinBox.value > 1? copiesSpinBox.value + " copies": "one copy"
console.log("Printing ", copies, " using ", allPrinters.currentText);
printDialog.close();
}
}
Button
{
text: qsTr("Ablehnen")
onClicked: printDialog.close();
}
}
Item
{
Layout.fillHeight: true
}
}
onVisibleChanged:
{
copiesSpinBox.value = 1
colorPrint.checked = true
}
Component.onCompleted:
{
printers = sys_printers.getPrinters()
if (sys_printers.getDefaultPrinter())
allPrinters.currentIndex = allPrinters.indexOfValue(sys_printers.getDefaultPrinter())
}
}

47
Gui/ReadMe.qml Normal file
View File

@@ -0,0 +1,47 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Window
{
property alias readMeWin: readMeWin
id: readMeWin
width: 400
height: 300
title: "PYQCRM - README"
color: palette.base
ScrollView
{
anchors.fill: parent
TextArea
{
id: readMe
anchors.fill: parent
readOnly: true
wrapMode: TextArea.Wrap
color: "darksalmon"
Component.onCompleted:
{
var filePath = "qrc:/README";
var xhr = new XMLHttpRequest();
xhr.open("GET", filePath, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE)
{
if (xhr.status === 200)
{
readMe.text = xhr.responseText;
}
else
{
readMe.text = qsTr("Datei nicht gefunden!");
}
}
};
xhr.send();
}
}
}
}

View File

@@ -21,12 +21,29 @@ RowLayout
id: dashBoard id: dashBoard
flat: true flat: true
text: qsTr("Dashboard") text: qsTr("Dashboard")
implicitWidth: dashBoard.implicitContentWidth + 10 implicitWidth: abrechnung.implicitContentWidth + 10
Layout.margins: 3
background: Rectangle
{
id: dashiBackie
border.width: dashBoard.activeFocus ? 2 : 1
border.color: "#888"
radius: 4
gradient: Gradient
{
GradientStop { position: 0 ; color: dashBoard.pressed ? "#000" : "#001" }
GradientStop { position: 1 ; color: dashBoard.pressed ? "#100" : "#000" }
}
}
onClicked: onClicked:
{ {
appLoader.source = "Dashboard.qml" appLoader.source = "Dashboard.qml"
dashiBackie.border.width = 2
kundiBackie.border.width = 1
mitoBackie.border.width = 1
invoBackie.border.width = 1
objBackie.border.width = 1
} }
} }
Button Button
@@ -34,11 +51,29 @@ RowLayout
id: kunden id: kunden
flat: true flat: true
text: qsTr("Kunden") text: qsTr("Kunden")
implicitWidth: kunden.implicitContentWidth + 10 implicitWidth: abrechnung.implicitContentWidth + 10
Layout.margins: 3
background: Rectangle
{
id: kundiBackie
border.width: kunden.activeFocus ? 2 : 1
border.color: "#888"
radius: 4
gradient: Gradient
{
GradientStop { position: 0 ; color: kunden.pressed ? "#000" : "#001" }
GradientStop { position: 1 ; color: kunden.pressed ? "#100" : "#000" }
}
}
onClicked: onClicked:
{ {
// TODO: here we should call the model // TODO: here we should call the model
appLoader.source = "CustomerTable.qml" appLoader.source = "CustomerTable.qml"
kundiBackie.border.width = 2
dashiBackie.border.width = 1
mitoBackie.border.width = 1
invoBackie.border.width = 1
objBackie.border.width = 1
} }
} }
@@ -47,10 +82,28 @@ RowLayout
id: objekt id: objekt
flat: true flat: true
text: qsTr("Objekt") text: qsTr("Objekt")
implicitWidth: objekt.implicitContentWidth + 10 implicitWidth: abrechnung.implicitContentWidth + 10
Layout.margins: 3
background: Rectangle
{
id: objBackie
border.width: objekt.activeFocus ? 2 : 1
border.color: "#888"
radius: 4
gradient: Gradient
{
GradientStop { position: 0 ; color: objekt.pressed ? "#000" : "#001" }
GradientStop { position: 1 ; color: objekt.pressed ? "#100" : "#000" }
}
}
onClicked: onClicked:
{ {
appLoader.source = "ObjectTable.qml" appLoader.source = "ObjectTable.qml"
objBackie.border.width = 2
dashiBackie.border.width = 1
kundiBackie.border.width = 1
mitoBackie.border.width = 1
invoBackie.border.width = 1
} }
} }
@@ -60,10 +113,28 @@ RowLayout
id: mitarbeiter id: mitarbeiter
flat: true flat: true
text: qsTr("Mitarbeiter") text: qsTr("Mitarbeiter")
implicitWidth: mitarbeiter.implicitContentWidth + 10 implicitWidth: abrechnung.implicitContentWidth + 10
Layout.margins: 3
background: Rectangle
{
id: mitoBackie
border.width: mitarbeiter.activeFocus ? 2 : 1
border.color: "#888"
radius: 4
gradient: Gradient
{
GradientStop { position: 0 ; color: mitarbeiter.pressed ? "#000" : "#001" }
GradientStop { position: 1 ; color: mitarbeiter.pressed ? "#100" : "#000" }
}
}
onClicked: onClicked:
{ {
appLoader.source = "EmployeeTable.qml" appLoader.source = "EmployeeTable.qml"
mitoBackie.border.width = 2
dashiBackie.border.width = 1
kundiBackie.border.width = 1
invoBackie.border.width = 1
objBackie.border.width = 1
} }
} }
@@ -73,6 +144,19 @@ RowLayout
flat: true flat: true
text: qsTr("Abrechnung") text: qsTr("Abrechnung")
implicitWidth: abrechnung.implicitContentWidth + 10 implicitWidth: abrechnung.implicitContentWidth + 10
Layout.margins: 3
background: Rectangle
{
id: invoBackie
border.width: abrechnung.activeFocus ? 2 : 1
border.color: "#888"
radius: 4
gradient: Gradient
{
GradientStop { position: 0 ; color: abrechnung.pressed ? "#000" : "#001" }
GradientStop { position: 1 ; color: abrechnung.pressed ? "#100" : "#000" }
}
}
} }
Item Item
@@ -88,9 +172,32 @@ RowLayout
icon.color: "red" icon.color: "red"
flat: true flat: true
Layout.rightMargin: 9 Layout.rightMargin: 9
onClicked: mainMenu.open()
Menu {
id: mainMenu
MenuItem
{
text: qsTr("Benutzer-Verwaltung")
onTriggered: appLoader.source = "UsersPage.qml"
}
MenuSeparator {}
MenuItem { text: qsTr("Als PDF exportieren") }
MenuSeparator {}
MenuItem { text: qsTr("Drucken") }
MenuItem
{
text: qsTr("Erweiterter Druck")
onTriggered: printerDialog.show()
}
MenuSeparator {}
MenuItem
{
text: qsTr("Über PYQCRM")
onTriggered: readMeWin.show()
}
}
} }
} }

16
Gui/UsersPage.qml Normal file
View File

@@ -0,0 +1,16 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
Item
{
anchors.fill: parent
Label
{
text: qsTr("Benutzer-Verwaltung")
anchors.centerIn: parent
font.pixelSize: 57
font.bold: true
}
}

View File

@@ -26,6 +26,16 @@ ApplicationWindow
visible: bad_config || !db_con ? false: true visible: bad_config || !db_con ? false: true
} }
PrinterDialog
{
id: printerDialog
}
ReadMe
{
id: readMeWin
}
Item Item
{ {
id: mainView id: mainView
@@ -34,6 +44,7 @@ ApplicationWindow
Loader Loader
{ {
id: appLoader id: appLoader
anchors anchors
{ {
left: parent.left left: parent.left

1
LICENSE Normal file
View File

@@ -0,0 +1 @@
Nicht zu verwenden ohne Zahlung!

54
README Normal file
View File

@@ -0,0 +1,54 @@
PYQCRM - Python QtQuick CRM System
Einleitung:
----------------
PYQCRM entstand als Teil einer Abschlusspraxis und dem Bedarf der TERO GmbH an einem Managementprogramm für den internen Gebrauch.
Erstellung:
----------------
Das Program wurde mit den folgenen Techologien entwickelt:
- IDE: Qt-Creator 6.8.x
- Framework: QtQuick - QML 6.8.x
- Sprache: Python 3.13.x
- Datenbank: MariaDB 10.11.x
- Sonstiges: JavaScript
Installation:
------------------
Möglicherweise ist für deine Plattform ein Installationspaket verfügbar. Prüfe es also zuerst.
Es gibt zwei möglichkeiten das Program zu verwenden:
Möglichkeit I:
1. Datenbank einrichten (MaraiDB SQL-Schema verfügbar)
2. Python installiert und eingerichtet
3. Das Program in einen bevorzugten Pfad kopieren.
4. Erstelle einen Link zum main.py-Skript und stelle ihn so ein, dass er mit deinem Python-Interpreter ausgeführt wird
Möglichkeit II:
1. Datenbank einrichten (MaraiDB SQL-Schema verfügbar)
2. Die ausführbare Version des Programs in einen bevorzugten Pfad kopieren
3. Erstelle einen Link zur ausführbaren Datei, die für dein System erstellt wurde (pyqcrm/pyqcrm.exe)
Kudos:
----------
Wenn dir dieses Kunstwerk gefällt, kannst du uns deine Wertschätzung einfach dadurch zeigen, dass du jedem von uns einen Bungalow, einen 760IL BMW, lebenslange Flugtickets inklusive Begleitung kaufst und als Geschenk ein paar Millionen Euro auf ein Schweizer Bankkonto überweist.
Team:
---------
Marcopolo
Schnacke
Renegade

View File

@@ -0,0 +1,88 @@
CRM für Objektbetreuung Reinigungsservice
Minimal Voraussetzung:
Mitarbeiter
- Dokumenten Management System (DMS)
- Arbeitszeitdokumentation
- Urlaubsplaner
- Arbeitnehmer anlegen
Nice To Have:
- WhatsApp
- Telefon
- Social Media Uploader
Dokumentenvorlagen
Kunden
- Kunden anlegen (Hausverwaltung Krefeld)
- Dokumenten Management System (DMS)
- Ansprechpartner anlegen
RG auch in CC Funktion
Nice To Have:
Dokumentenvorlagen
Dashboard
Abrechnung
- Rechnung schreiben (Zugferd Modus)
- Fixkostenerfassung
Rechnungsarchiv
Mahnfunktion
Objekt
- Objekt anlegen
- Ansprechpartner anlegen
- Dokumenten Management System (DMS)
Str. (Pflicht)
Hausnummer (Pflicht)
PLZ
Ort (Pflicht)
Parteien (Anzahl)
Stockwerke (Anzahl)
Zwischenetage (ja/nein)
Aufzug (ja/nein)
Fenster (ja/nein) anschließend Anzahl + ohne Leiter erreichbar (ja/nein)
Besonderheiten (Infofeld)
Kontaktdaten Hausmeister / Beirat
Reinigungsmittel zu finden? ( Wo ist es im Kellerraum, Dachgeschoss, 2 Tür von links?)
Foto Upload wäre toll ;-)
Leistungen
Treppenhausreinigung
Garten
siehe Homepage !!!
Angebot
Auftrag
- Arbeitsauftrag anlegen
Pflegehinweise zum Objekt
BG Sicherheitsdatenblätter
Reinigungsmittel erhalten am ?
Preis ab Datum
Objektkontrolle (Wann wurde das Objekt das letzte Mal kontrolliert?) Ähnlich wie Preis mit Datum
Preise
Schlüssel
Auswertung
Stundenkalender

1
backup.pyqrec Normal file
View File

@@ -0,0 +1 @@
zIgY4d8ORJ0HZpG7y8/XeS84mKHFcvNaMmCxdirT6ebjApHlo5XVXspy3ENIEvrZczSDRugR0sAVVt8StqZ2gGAr42tIwFF9Uwl7YBMi72+iGIkwyIGX/Jw3OiHYubkXEooZLYX1MYPOC91ppVnZG0PA0IYdpDofq5inFfxpPBwMdcJxvtZPLhIX2y7Fn3m1/lsWe+e2EBwDGxnZjUjPMsRFMjswBv20EOHk46OuNFwlDyn+w9ZDoJfhF6HKYqNxnBnN90KEUygTYGWk.nfaytDW7Z0Nn2/5d22/ciQ==

View File

@@ -1,29 +1,88 @@
CRM für Objektbetreuung Reinigungsservice CRM für Objektbetreuung Reinigungsservice
Aktueller Stand CRM Sebastian
Umsetzung mit Python + QML
- Kunden anlegen
- Abrufen und anzeigen vorhandender Daten aus der Datenbank
- GUI vorhanden
Minimal Voraussetzung: Minimal Voraussetzung:
- Kunden anlegen (Hausverwaltung Krefeld)
- Objekt anlegen Mitarbeiter
- Ansprechpartner anlegen - Dokumenten Management System (DMS)
- Arbeitnehmer anlegen
- Arbeitsauftrag anlegen
- Rechnung schreiben (Zugferd Modus)
- Dokumenten Managment System (DMS)
- Arbeitszeitdokumentation - Arbeitszeitdokumentation
- Urlaubsplaner - Urlaubsplaner
- Arbeitnehmer anlegen
Nice To Have: Nice To Have:
- WhatsApp - WhatsApp
- Telefon - Telefon
- Social Media Uploader - Social Media Uploader
Dokumentenvorlagen
Kunden
- Kunden anlegen (Hausverwaltung Krefeld)
- Dokumenten Management System (DMS)
- Ansprechpartner anlegen
RG auch in CC Funktion
Nice To Have:
Dokumentenvorlagen
Dashboard
Abrechnung
- Rechnung schreiben (Zugferd Modus)
- Fixkostenerfassung
Rechnungsarchiv
Mahnfunktion
Objekt
- Objekt anlegen
- Ansprechpartner anlegen
- Dokumenten Management System (DMS)
Str. (Pflicht)
Hausnummer (Pflicht)
PLZ
Ort (Pflicht)
Parteien (Anzahl)
Stockwerke (Anzahl)
Zwischenetage (ja/nein)
Aufzug (ja/nein)
Fenster (ja/nein) anschließend Anzahl + ohne Leiter erreichbar (ja/nein)
Besonderheiten (Infofeld)
Kontaktdaten Hausmeister / Beirat
Reinigungsmittel zu finden? ( Wo ist es im Kellerraum, Dachgeschoss, 2 Tür von links?)
Foto Upload wäre toll ;-)
Leistungen
Treppenhausreinigung
Garten
siehe Homepage !!!
Angebot
Auftrag
- Arbeitsauftrag anlegen
Pflegehinweise zum Objekt
BG Sicherheitsdatenblätter
Reinigungsmittel erhalten am ?
Preis ab Datum
Objektkontrolle (Wann wurde das Objekt das letzte Mal kontrolliert?) Ähnlich wie Preis mit Datum
Preise
Schlüssel
Auswertung
Stundenkalender

File diff suppressed because it is too large Load Diff

View File

@@ -50,6 +50,19 @@ function parseForm(...form)
{ {
data_form[form[i].children[j].name] = form[i].children[j].checked data_form[form[i].children[j].name] = form[i].children[j].checked
} }
else if (form[i].children[j].toString().startsWith("SpinBox"))
{
data_form[form[i].children[j].name] = form[i].children[j].value
}
// else if (form[i].children[j].toString().startsWith("QQuickContentItem"))
// {
// console.log(form[i].children[j].children.children)
// for (var k = 0; k < form[i].children[j].length; k++)
// {
// console.log(form[i].children[j].name)
// }
// }
} }
} }
return data_form return data_form

View File

@@ -41,7 +41,7 @@ class ConfigLoader(QObject):
else: else:
config_dir.mkdir(0o750, True, True) config_dir.mkdir(0o750, True, True)
@Slot(dict, result= bool) @Slot(dict, result = bool)
def setConfig(self, app_config): def setConfig(self, app_config):
# print(f"In {__file__} file, setConfig()") # print(f"In {__file__} file, setConfig()")
if not self.__config: if not self.__config:

View File

@@ -8,6 +8,7 @@ class BusinessDAO(QObject):
newBusinessAdded = Signal() newBusinessAdded = Signal()
__cur = None __cur = None
__all_cols = None
def __init__(self): def __init__(self):
#print(f"*** File: {__file__}, init()") #print(f"*** File: {__file__}, init()")
@@ -27,6 +28,17 @@ class BusinessDAO(QObject):
except mariadb.Error as e: except mariadb.Error as e:
print(str(e)) print(str(e))
def getOneBusiness(self, business_id, enc_key = None):
try:
if self.__cur:
self.__cur.callproc("getCustomer", (business_id, enc_key,))
#self.__all_cols = [desc[0] for desc in self.__cur.description]
return self.__cur.fetchall() #, self.__all_cols
else:
return None #, None
except mariadb.Error as e:
print(str(e))
def addBusiness(self, data, contact_id): def addBusiness(self, data, contact_id):
try: try:
if self.__cur: if self.__cur:

View File

@@ -63,8 +63,11 @@ from ..ConfigLoader import ConfigLoader
class BusinessModel(QAbstractTableModel): class BusinessModel(QAbstractTableModel):
__visible_index = {} __visible_index = {}
__visible_columns = None
__col_name = "" __col_name = ""
__business_dao = None __business_dao = None
__business = None
__business_dict = {'business':{}} #,'contact':{}}
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@@ -80,13 +83,29 @@ class BusinessModel(QAbstractTableModel):
self.__data = rows self.__data = rows
self.endResetModel() self.endResetModel()
def __getBusinessInfo(self):
self.__business_dict['business']['id'] = self.__business[0][0]
self.__business_dict['business']['contactid'] = self.__business[0][1]
self.__business_dict['business']['company'] = self.__business[0][2]
self.__business_dict['business']['phone'] = self.__business[0][3]
self.__business_dict['business']['cell'] = self.__business[0][4]
self.__business_dict['business']['email'] = self.__business[0][5]
self.__business_dict['business']['website'] = self.__business[0][6]
self.__business_dict['business']['ceo'] = self.__business[0][7]
self.__business_dict['business']['info'] = self.__business[0][8]
self.__business_dict['business']['tax'] = self.__business[0][9]
self.__business_dict['business']['street'] = self.__business[0][10]
self.__business_dict['business']['house'] = self.__business[0][11]
self.__business_dict['business']['zip'] = self.__business[0][12]
self.__business_dict['business']['city'] = self.__business[0][13]
def rowCount(self, parent= QModelIndex()): def rowCount(self, parent= QModelIndex()):
return len (self.__data) return len (self.__data)
def columnCount(self, parent= QModelIndex()): def columnCount(self, parent= QModelIndex()):
return len(self.__visible_columns) - 1 return len(self.__visible_columns) - 1
def data(self, index, role= Qt.DisplayRole): def data(self, index, role = Qt.DisplayRole):
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
row = self.__data[index.row()] row = self.__data[index.row()]
return row[index.column() + 1] return row[index.column() + 1]
@@ -113,7 +132,18 @@ class BusinessModel(QAbstractTableModel):
@Slot(int) @Slot(int)
def onRowClicked(self, row): def onRowClicked(self, row):
print(f"Selected table row: {row}, corresponding DB ID: {self.__data[row][0]}") #print(self.__data)
#print(f"Selected table row: {row}, corresponding DB ID: {self.__data[row][0]}")
if not self.__business_dict['business'] or self.__data[row][0] != self.__business_dict['business']['id']:
self.__business = self.__business_dao.getOneBusiness(self.__data[row][0], self.__key)
#print(self.__business)
self.__getBusinessInfo()
# self.__getContactInfo()
# print(self.__business_dict)
@Slot(result = dict)
def getClientDetails(self):
return self.__business_dict
@Slot(str) @Slot(str)
def viewCriterion(self, criterion): def viewCriterion(self, criterion):
@@ -134,5 +164,3 @@ class BusinessModel(QAbstractTableModel):
def updateTable(self): def updateTable(self):
pass pass

View File

@@ -30,4 +30,15 @@ class ContactDAO:
except Exception as e: except Exception as e:
print("PYT: " + str(e)) print("PYT: " + str(e))
def getContact(self, contact_id, enc_key = None):
try:
if self.__cur:
self.__cur.callproc("getCustomerContact", (contact_id, enc_key,))
#self.__all_cols = [desc[0] for desc in self.__cur.description]
return self.__cur.fetchall() #, self.__all_cols
else:
return None #, None
except mariadb.Error as e:
print(str(e))

View File

@@ -5,6 +5,10 @@ import logging
class ContactModel(QObject): class ContactModel(QObject):
contactIdReady = Signal(int) contactIdReady = Signal(int)
__contact = None
__contact_dict = {'contact':{}}
def __init__(self): def __init__(self):
super().__init__() super().__init__()
# print(f"*** File: {__file__}, __init__()") # print(f"*** File: {__file__}, __init__()")
@@ -27,5 +31,29 @@ class ContactModel(QObject):
i = ContactDAO().addContact(contact, self.__key) i = ContactDAO().addContact(contact, self.__key)
self.contactIdReady.emit(i) self.contactIdReady.emit(i)
def __getContact(self, contact):
self.__contact = ContactDAO().getContact(contact, self.__key)
self.__getContactInfo()
@Slot(int, result = dict)
def getContactDetails(self, contact):
self.__getContact(contact)
#print(self.__contact_dict)
return self.__contact_dict
def __getContactInfo(self):
self.__contact_dict['contact']['id'] = self.__contact[0][0]
self.__contact_dict['contact']['salute'] = self.__contact[0][1]
self.__contact_dict['contact']['fname'] = self.__contact[0][2].decode("utf-8")
self.__contact_dict['contact']['lname'] = self.__contact[0][3].decode("utf-8")
self.__contact_dict['contact']['phone'] = self.__contact[0][4].decode("utf-8")
self.__contact_dict['contact']['cell'] = self.__contact[0][5].decode("utf-8")
self.__contact_dict['contact']['position'] = self.__contact[0][6]
self.__contact_dict['contact']['email'] = self.__contact[0][7].decode("utf-8")
self.__contact_dict['contact']['birthday'] = self.__contact[0][8].decode("utf-8")
self.__contact_dict['contact']['priority'] = "Ja" if self.__contact[0][9] else "Nein"
self.__contact_dict['contact']['invoice'] = "Ja" if self.__contact[0][10] else "Nein"
self.__contact_dict['contact']['reminder'] = "Ja" if self.__contact[0][11] else "Nein"

50
lib/DB/EmployeeDAO.py Normal file
View File

@@ -0,0 +1,50 @@
from .DbManager import DbManager
import json
import mariadb
from PySide6.QtCore import QObject, Signal
from ..PyqcrmFlags import PyqcrmAppliEmpyFlags
class EmployeeDAO(QObject):
newEmployeeAdded = Signal()
__cur = None
__all_cols = None
def __init__(self):
super().__init__()
self.__con = DbManager().getConnection()
if self.__con:
self.__cur = self.__con.cursor()
def getEmployees(self, enc_key, criterion = "Alle", processed = False, fired = False, every_state = True):
try:
if self.__cur:
self.__cur.callproc("getEmployeeTable", (criterion, processed, fired, every_state, enc_key, ))
self.__all_cols = [desc[0] for desc in self.__cur.description]
return self.__cur.fetchall(), self.__all_cols
else:
return None, None
except mariadb.Error as e:
print(str(e))
def getEmployee(self, employee_id, enc_key = None):
try:
if self.__cur:
self.__cur.callproc("getEmployee", (employee_id, enc_key,))
#self.__all_cols = [desc[0] for desc in self.__cur.description]
return self.__cur.fetchall() #, self.__all_cols
else:
return None #, None
except mariadb.Error as e:
print(str(e))
def addEmployee(self, data, enc_key, applicant = True):
try:
if self.__cur:
self.__cur.callproc("addApplicant", (json.dumps(data), applicant, enc_key,))
self.__con.commit()
self.newEmployeeAdded.emit()
except mariadb.Error as e:
print(str(e))

90
lib/DB/EmployeeModel.py Normal file
View File

@@ -0,0 +1,90 @@
from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Slot, Signal
from .EmployeeDAO import EmployeeDAO
from ..PyqcrmFlags import PyqcrmFlags, PyqcrmAppliEmpyFlags
from ..ConfigLoader import ConfigLoader
import re
class EmployeeModel(QAbstractTableModel):
__data = None
__employee_dao = None
__visible_index = None
__visible_columns = None
__col_name = ""
__employee_dao = None
__col_skip = 2
__everyone = True
def __init__(self):
super().__init__()
self.__employee_dao = EmployeeDAO()
self.__employee_dao.newEmployeeAdded.connect(self.__refreshView)
self.__conf = ConfigLoader().getConfig()
self.__key = self.__conf['pyqcrm']['ENCRYPTION_KEY']
self.__getData()
@Slot(dict, bool)
def addEmployee(self, new_employee, applicant = True):
new_employee['worklicense'] = int(new_employee['worklicense'])
new_employee['residencetype'] = int(new_employee['residencetype'])
self.__employee_dao.addEmployee(new_employee, self.__key, applicant)
@Slot(str)
def viewCriterion(self, criterion, processed = False, fired = False):
self.__getData(criterion, processed, fired)
@Slot()
def __refreshView(self):
self.__getData()
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)
self.__data = rows
self.endResetModel()
def rowCount(self, parent= QModelIndex()):
return len (self.__data)
def columnCount(self, parent= QModelIndex()):
return len(self.__visible_columns) - self.__col_skip
@Slot(str, bool, bool, bool)
def viewCriterion(self, criterion, processed, fired, every_state):
self.__everyone = True if criterion == 'Alle' else False
if self.__everyone and criterion != "Alle":
self.__col_skip = 2
else:
self.__col_skip = 2
self.__getData(criterion, processed, fired, every_state)
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")
if applicant_col == 2 and self.__everyone:
tr = 'Ja' if tr == 1 else 'Nein'
else:
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):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
self.__col_name = self.__visible_columns[section + self.__col_skip]
return self.__col_name
return super().headerData(section, orientation, role)
@Slot(int)
def onRowClicked(self, row):
#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)

26
lib/DB/ObjectDAO.py Normal file
View File

@@ -0,0 +1,26 @@
from .DbManager import DbManager
import json
import mariadb
from PySide6.QtCore import QObject, Signal
from ..PyqcrmFlags import PyqcrmAppliEmpyFlags
class ObjectDAO(QObject):
newObjectAdded = Signal()
def __init__(self):
super().__init__()
#print(f"*** File: {__file__}, __init__()")
self.__con = DbManager().getConnection()
if self.__con:
self.__cur = self.__con.cursor()
def addObject(self, new_object, new_objcontact, enc_key):
try:
if self.__cur:
self.__cur.callproc("addObject", (json.dumps(new_object), json.dumps(new_objcontact), enc_key,))
self.__con.commit()
# self.newEmployeeAdded.emit()
except mariadb.Error as e:
print(str(e))

94
lib/DB/ObjectModel.py Normal file
View File

@@ -0,0 +1,94 @@
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
class ObjectModel(QAbstractTableModel):
__data = None
__object_dao = None
__visible_index = None
__visible_columns = None
__col_name = ""
__employee_dao = None
__col_skip = 2
__everyone = True
def __init__(self):
super().__init__()
self.__object_dao = ObjectDAO()
self.__object_dao.newObjectAdded.connect(self.__refreshView)
self.__conf = ConfigLoader().getConfig()
self.__key = self.__conf['pyqcrm']['ENCRYPTION_KEY']
#self.__getData()
@Slot(dict, list, bool)
def addObject(self, new_object, new_objcontact):
print(new_object)
print(new_objcontact)
self.__object_dao.addObject(new_object, new_objcontact, self.__key)
# @Slot(str)
# def viewCriterion(self, criterion, processed = False, fired = False):
# self.__getData(criterion, processed, fired)
@Slot()
def __refreshView(self):
self.__getData()
# 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)
# self.__data = rows
# self.endResetModel()
# def rowCount(self, parent= QModelIndex()):
# return len (self.__data)
# def columnCount(self, parent= QModelIndex()):
# return len(self.__visible_columns) - self.__col_skip
# @Slot(str, bool, bool, bool)
# def viewCriterion(self, criterion, processed, fired, every_state):
# self.__everyone = True if criterion == 'Alle' else False
# if self.__everyone and criterion != "Alle":
# self.__col_skip = 2
# else:
# self.__col_skip = 2
# self.__getData(criterion, processed, fired, every_state)
# 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")
# if applicant_col == 2 and self.__everyone:
# tr = 'Ja' if tr == 1 else 'Nein'
# else:
# 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):
# if orientation == Qt.Horizontal and role == Qt.DisplayRole:
# self.__col_name = self.__visible_columns[section + self.__col_skip]
# return self.__col_name
# return super().headerData(section, orientation, role)
# @Slot(int)
# def onRowClicked(self, row):
# #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)

View File

@@ -1,9 +1,13 @@
from .DbManager import DbManager from .DbManager import DbManager
from ..PyqcrmFlags import PyqcrmFlags from ..PyqcrmFlags import PyqcrmFlags
from ..Vermasseln import Vermasseln from ..Vermasseln import Vermasseln
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput #from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput : Not working well with Nuitka
import soundfile as sf
import sounddevice as sd
from .UserDAO import UserDAO from .UserDAO import UserDAO
from PySide6.QtCore import Slot, QObject, Signal, QUrl from PySide6.QtCore import Slot, QObject, Signal, QUrl, QFile
import tempfile
class UserManager(QObject): class UserManager(QObject):
@@ -61,12 +65,24 @@ class UserManager(QObject):
if user: if user:
self.__checkPassword(password, user[2]) self.__checkPassword(password, user[2])
else: else:
player = QMediaPlayer(self) fail_src = ":/sounds/fail2c.ogg"
audioOutput = QAudioOutput(self) with tempfile.NamedTemporaryFile(suffix='.ogg') as ogg_file:
player.setAudioOutput(audioOutput) failure_sound = QFile(fail_src)
player.setSource(QUrl("qrc:/sounds/fail2c.ogg")) if not failure_sound.open(QFile.ReadOnly):
audioOutput.setVolume(150) print(f"Failed to open resource file: {fail_src}")
player.play() else:
ogg_file.write(failure_sound.readAll())
ogg_path = ogg_file.name
fail, samplerate = sf.read(ogg_path)
sd.play(fail, samplerate)
### Not working with Nuitka
# player = QMediaPlayer(self)
# audioOutput = QAudioOutput(self)
# player.setAudioOutput(audioOutput)
# player.setSource(QUrl("qrc:/sounds/fail2c.ogg"))
# audioOutput.setVolume(150)
# player.play()
def __checkPassword(self, password, hash_password): def __checkPassword(self, password, hash_password):
pw_list = hash_password.split("$") pw_list = hash_password.split("$")

23
lib/Printers.py Normal file
View File

@@ -0,0 +1,23 @@
from PySide6.QtCore import QObject, Slot
from PySide6.QtPrintSupport import QPrinterInfo
class Printers(QObject):
__printers = None
__default_printer = None
__default_printer_name = None
__available_printers = []
def __init__(self):
super().__init__()
self.__printers = QPrinterInfo.availablePrinters()
self.__available_printers = QPrinterInfo.availablePrinterNames()
self.__default_printer = QPrinterInfo.defaultPrinter()
self.__default_printer_name = QPrinterInfo.defaultPrinterName()
@Slot(result = list)
def getPrinters(self):
return self.__available_printers
@Slot(result = str)
def getDefaultPrinter(self):
return self.__default_printer_name

View File

@@ -5,4 +5,9 @@ class PyqcrmFlags(IntFlag):
ADMIN = 1 ADMIN = 1
USER = 2 USER = 2
class PyqcrmAppliEmpyFlags(IntFlag):
ALL = 0
APPLICANT = 1
EMPLOYEE = 2

81
lib/PyqcrmPDF.py Normal file
View File

@@ -0,0 +1,81 @@
from reportlab.lib.pagesizes import A4 #, letter...etc
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
'''
Need to check for sender and receiver sections
Other alternatives can be pdf-gen, pdf-generator, pdf-play, pdf34, abdul-987-pdf
'''
class PyqcrmPDF:
__pyq_doc = None
__pyq_pdf = None
__pyq_usable_width = 0
__pyq_usable_height = 0
__pyq_lr_margin = 20
__pyq_tb_margin = 25
__line = 0
__line_height = 14
__doc_title = "PYQCRM PDF Document"
__doc_author = "The PYQCRM Team"
__doc_subject = "PYQCRM Document"
def __init__(self, doc_title, doc_subject, pdf_file):
self.__pyq_usable_width = A4[0] - self.__pyq_lr_margin - self.__pyq_lr_margin
self.__pyq_usable_height = A4[1] - self.__pyq_tb_margin - self.__pyq_tb_margin
self.__line = self.__pyq_usable_height + self.__pyq_tb_margin
self.__pyq_pdf = canvas.Canvas(pdf_file, pagesize=A4)
self.__pyq_pdf.setAuthor(self.__doc_author)
self.__pyq_pdf.setTitle(doc_title if doc_title else self.__doc_title)
self.__pyq_pdf.setSubject(doc_subject if doc_subject else self.__doc_subject)
self.__pyq_doc = self.__pyq_pdf.beginText(self.__pyq_lr_margin, self.__line)
self.__pyq_doc.setFont("Helvetica", 12)
def addLine(self, line):
#self.__pyq_pdf.drawString(self.__pyq_lr_margin, self.__line, line) : Need to check if it does the trick!
# print(f"Line No.: {self.__line}")
# print(f"Line: {line}")
if self.__pyq_doc.getY() < self.__pyq_tb_margin:
# print("creating a new page...")
self.__pyq_pdf.drawText(self.__pyq_doc)
self.__pyq_pdf.showPage()
self.__line = self.__pyq_usable_height + self.__pyq_tb_margin
# print(f"Line No.: {self.__line}")
self.__pyq_doc = self.__pyq_pdf.beginText(self.__pyq_lr_margin, self.__line)
self.__pyq_doc.setFont("Helvetica", 12)
if pdfmetrics.stringWidth(line, "Helvetica", 12) > self.__pyq_usable_width:
# print(f"Line width: {pdfmetrics.stringWidth(line, 'Helvetica', 12)}, Available width: {self.__pyq_usable_width}")
words = line.split(' ')
line = ''
for word in words:
# print(f"Line: {line}")
if self.__pyq_doc.getY() < self.__pyq_tb_margin:
# print("creating a new page...")
self.__pyq_pdf.drawText(self.__pyq_doc)
self.__pyq_pdf.showPage()
self.__line = self.__pyq_usable_height + self.__pyq_tb_margin
# print(f"Line No.: {self.__line}")
self.__pyq_doc = self.__pyq_pdf.beginText(self.__pyq_lr_margin, self.__line)
self.__pyq_doc.setFont("Helvetica", 12)
if pdfmetrics.stringWidth(line + word + ' ', "Helvetica", 12) <= self.__pyq_usable_width:
line = line + word + ' '
else:
self.__pyq_doc.textLine(line)
line = word + ' '
# print(f"Last line: {line}")
if line:
# print(f"Available line: {line}")
self.__pyq_doc.textLine(line)
self.__line = self.__line + self.__line_height
def saveDoc(self):
self.__pyq_pdf.drawText(self.__pyq_doc)
self.__pyq_pdf.showPage()
self.__pyq_pdf.save()

23
main.py
View File

@@ -1,4 +1,5 @@
# # !/home/linuxero/proj/tero/pyqcrm/.qtcreator/venv-3.13.1/bin/python3 # # !/home/linuxero/proj/tero/pyqcrm/.qtcreator/venv-3.13.1/bin/python3
import os
import sys import sys
import logging import logging
from PySide6.QtGui import QGuiApplication from PySide6.QtGui import QGuiApplication
@@ -13,9 +14,12 @@ from lib.DB.UserManager import UserManager
from lib.DB.AddressModel import AddressModel from lib.DB.AddressModel import AddressModel
from lib.DB.BTypeModel import BTypeModel from lib.DB.BTypeModel import BTypeModel
from lib.DB.ContactModel import ContactModel from lib.DB.ContactModel import ContactModel
from lib.DB.EmployeeModel import EmployeeModel
from lib.DB.ObjectModel import ObjectModel
from lib.Printers import Printers
os.environ['QML_XHR_ALLOW_FILE_READ'] = '1'
# [pyqcrm] # [pyqcrm]
# program-name="" # program-name=""
@@ -35,14 +39,18 @@ address_model = None
business_model = None business_model = None
business_type = None business_type = None
contact_model = None contact_model = None
employee_model = None
object_model = None
printers = None
user = None user = None
def initializeProgram(): def initializeProgram():
#print(f"In {__file__} file, initializeProgram()") #print(f"In {__file__} file, initializeProgram()")
global address_model, bad_config, business_model, user, business_type, contact_model, db_con global address_model, bad_config, business_model, user, business_type, contact_model, employee_model, object_model, db_con, printers
if not bad_config: if not bad_config:
dbconf = config.getConfig()['database'] dbconf = config.getConfig()['database']
DbManager(dbconf) DbManager(dbconf)
printers = Printers()
if DbManager().getConnection(): if DbManager().getConnection():
db_con = True db_con = True
user = UserManager() user = UserManager()
@@ -50,18 +58,22 @@ def initializeProgram():
address_model = AddressModel() address_model = AddressModel()
business_type = BTypeModel() business_type = BTypeModel()
contact_model = ContactModel() contact_model = ContactModel()
employee_model = EmployeeModel()
object_model = ObjectModel()
publishContext() publishContext()
bad_config = False bad_config = False
def publishContext(): def publishContext():
# print(f"In {__file__} file, publishContext()") # print(f"In {__file__} file, publishContext()")
global engine, address_model, bad_config, business_model, user, business_type, contact_model global engine, address_model, bad_config, business_model, user, business_type, contact_model, object_model, employee_model, printers
engine.rootContext().setContextProperty("loggedin_user", user) engine.rootContext().setContextProperty("loggedin_user", user)
engine.rootContext().setContextProperty("business_model", business_model) engine.rootContext().setContextProperty("business_model", business_model)
engine.rootContext().setContextProperty("address_model", address_model) engine.rootContext().setContextProperty("address_model", address_model)
engine.rootContext().setContextProperty("business_type", business_type) engine.rootContext().setContextProperty("business_type", business_type)
engine.rootContext().setContextProperty("contact_model", contact_model) engine.rootContext().setContextProperty("contact_model", contact_model)
engine.rootContext().setContextProperty("employee_model", employee_model)
engine.rootContext().setContextProperty("object_model", object_model)
if __name__ == "__main__": if __name__ == "__main__":
#QResource.registerResource("rc_qml.py") #QResource.registerResource("rc_qml.py")
@@ -76,14 +88,13 @@ if __name__ == "__main__":
config = ConfigLoader() config = ConfigLoader()
if not config.getConfig(): if not config.getConfig():
bad_config = True bad_config = True
config.configurationReady.connect(initializeProgram) config.configurationReady.connect(initializeProgram)
else: else:
initializeProgram() initializeProgram()
engine.rootContext().setContextProperty("sys_printers", printers)
engine.rootContext().setContextProperty("bad_config", bad_config) # print(f"Fehler: {i}") engine.rootContext().setContextProperty("bad_config", bad_config) # print(f"Fehler: {i}")
engine.rootContext().setContextProperty("db_con", db_con) engine.rootContext().setContextProperty("db_con", db_con)
engine.rootContext().setContextProperty("config", config) engine.rootContext().setContextProperty("config", config)

View File

@@ -18,6 +18,12 @@
"lib/DB/BTypeModel.py", "lib/DB/BTypeModel.py",
"lib/DB/BTypeDAO.py", "lib/DB/BTypeDAO.py",
"lib/DB/ContactDAO.py", "lib/DB/ContactDAO.py",
"lib/DB/ContactModel.py" "lib/DB/ContactModel.py",
"lib/DB/EmployeeModel.py",
"lib/DB/EmployeeDAO.py",
"lib/Printers.py",
"lib/PyqcrmPDF.py",
"lib/DB/ObjectDAO.py",
"lib/DB/ObjectModel.py"
] ]
} }

View File

@@ -1,325 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 14.0.2, 2025-01-08T09:17:38. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{39e37ca7-c3e2-4c38-a716-3e864b0bb4d2}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="qlonglong">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">2</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.CTest">false</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<value type="bool" key="AutoTest.ApplyFilter">false</value>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">6</value>
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
<valuemap type="QVariantMap" key="CppEditor.QuickFix">
<value type="bool" key="UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Python 3.13.0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Python 3.13.0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{78860287-dff8-46dd-a381-8b430dbab0da}</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:\Users\gatze\Desktop\pyqcrm</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Python.PysideBuildStep</value>
<value type="QString" key="Python.PySideProjectTool">C:\Users\gatze\AppData\Roaming\Python\Python313\Scripts\pyside6-project.exe</value>
<value type="QString" key="Python.PySideUic">C:\Users\gatze\AppData\Roaming\Python\Python313\Scripts\pyside6-uic.exe</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Python 3.13.0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Python.PySideBuildConfiguration</value>
<value type="QString" key="python">C:/Users/gatze/AppData/Local/Programs/Python/Python313/python.exe</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:\Users\gatze\Desktop\pyqcrm\.qtcreator\Python_3_13_0venv</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Python.PysideBuildStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Python 3.13.0 virtuelle Umgebung</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Python.PySideBuildConfiguration</value>
<value type="QString" key="python">C:/Users/gatze/Desktop/pyqcrm/.qtcreator/Python_3_13_0venv/Scripts/python.exe</value>
<value type="QString" key="venv">C:/Users/gatze/Desktop/pyqcrm/.qtcreator/Python_3_13_0venv</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph &quot;dwarf,4096&quot; -F 250</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">main.py</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">PythonEditor.RunConfiguration.C:/Users/gatze/Desktop/pyqcrm/main.py</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">C:/Users/gatze/Desktop/pyqcrm/main.py</value>
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
<value type="QString" key="PythonEditor.RunConfiguation.Script">C:\Users\gatze\Desktop\pyqcrm\main.py</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">C:/Users/gatze/Desktop/pyqcrm</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph &quot;dwarf,4096&quot; -F 250</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">lib\DB\DbManager.py</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">PythonEditor.RunConfiguration.C:/Users/gatze/Desktop/pyqcrm/lib/DB/DbManager.py</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">C:/Users/gatze/Desktop/pyqcrm/lib/DB/DbManager.py</value>
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
<value type="QString" key="PythonEditor.RunConfiguation.Script">C:\Users\gatze\Desktop\pyqcrm\lib\DB\DbManager.py</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">C:/Users/gatze/Desktop/pyqcrm/lib/DB</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">2</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.1</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Python 3.12.6</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Python 3.12.6</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{2db3a2fc-21bd-4c08-acba-70fdc903d42a}</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:\Users\gatze\Desktop\pyqcrm\.qtcreator\Python_3_12_6venv</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Python.PysideBuildStep</value>
<value type="QString" key="Python.PySideProjectTool">C:\Users\gatze\Desktop\pyqcrm\.qtcreator\Python_3_12_6venv\Scripts\pyside6-project.exe</value>
<value type="QString" key="Python.PySideUic">C:\Users\gatze\Desktop\pyqcrm\.qtcreator\Python_3_12_6venv\Scripts\pyside6-uic.exe</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Erstellen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Bereinigen</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Python 3.12.6 virtuelle Umgebung</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Python.PySideBuildConfiguration</value>
<value type="QString" key="python">C:/Users/gatze/Desktop/pyqcrm/.qtcreator/Python_3_12_6venv/Scripts/python.exe</value>
<value type="QString" key="venv">C:/Users/gatze/Desktop/pyqcrm/.qtcreator/Python_3_12_6venv</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph &quot;dwarf,4096&quot; -F 250</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">main.py</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">PythonEditor.RunConfiguration.C:/Users/gatze/Desktop/pyqcrm/main.py</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">C:/Users/gatze/Desktop/pyqcrm/main.py</value>
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
<value type="QString" key="PythonEditor.RunConfiguation.Script">C:\Users\gatze\Desktop\pyqcrm\main.py</value>
<value type="int" key="RunConfiguration.UseCppDebugger">0</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
<value type="int" key="RunConfiguration.UsePythonDebugger">0</value>
<value type="int" key="RunConfiguration.UseQmlDebugger">0</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">C:/Users/gatze/Desktop/pyqcrm</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph &quot;dwarf,4096&quot; -F 250</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">lib\Vermasseln.py</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">PythonEditor.RunConfiguration.C:/Users/gatze/Desktop/pyqcrm/lib/Vermasseln.py</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">C:/Users/gatze/Desktop/pyqcrm/lib/Vermasseln.py</value>
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
<value type="QString" key="PythonEditor.RunConfiguation.Script">C:\Users\gatze\Desktop\pyqcrm\lib\Vermasseln.py</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">C:/Users/gatze/Desktop/pyqcrm/lib</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">2</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="qlonglong">2</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@@ -18,5 +18,7 @@
<file>fonts/LittleBirdsRegular.ttf</file> <file>fonts/LittleBirdsRegular.ttf</file>
<file>fonts/ReginaldScript.ttf</file> <file>fonts/ReginaldScript.ttf</file>
<file>images/account.svg</file> <file>images/account.svg</file>
<file>README</file>
<file>LICENSE</file>
</qresource> </qresource>
</RCC> </RCC>

11
qml.qrc
View File

@@ -26,18 +26,21 @@
<file>Gui/AddObjectEmployee.qml</file> <file>Gui/AddObjectEmployee.qml</file>
<file>Gui/AddApplicant.qml</file> <file>Gui/AddApplicant.qml</file>
<file>Gui/ApplicantPersonalData.qml</file> <file>Gui/ApplicantPersonalData.qml</file>
<file>Gui/ApplicantContactData.qml</file>
<file>Gui/ApplicantBankData.qml</file> <file>Gui/ApplicantBankData.qml</file>
<file>Gui/ApplicantNationality.qml</file>
<file>Gui/ApplicantNationalInsurance.qml</file> <file>Gui/ApplicantNationalInsurance.qml</file>
<file>Gui/ApplicantMiniJob.qml</file>
<file>Gui/ApplicantVarious.qml</file> <file>Gui/ApplicantVarious.qml</file>
<file>Gui/ApplicantBirthData.qml</file>
<file>Gui/CustomersTable.qml</file> <file>Gui/CustomersTable.qml</file>
<file>Gui/CustomerDetails.qml</file> <file>Gui/CustomerDetails.qml</file>
<file>Gui/ObjectsTable.qml</file> <file>Gui/ObjectsTable.qml</file>
<file>Gui/EmployeesTable.qml</file> <file>Gui/EmployeesTable.qml</file>
<file>Gui/EmployeeDetails.qml</file> <file>Gui/EmployeeDetails.qml</file>
<file>Gui/ObjectDetails.qml</file> <file>Gui/ObjectDetails.qml</file>
<file>Gui/AddNewObject.qml</file>
<file>Gui/PrinterDialog.qml</file>
<file>Gui/CustomerContactDetails.qml</file>
<file>Gui/NoCustomerContact.qml</file>
<file>Gui/CustomerDetailsView.qml</file>
<file>Gui/ReadMe.qml</file>
<file>Gui/UsersPage.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -4,6 +4,10 @@ pycryptodome
psutil psutil
toml toml
mariadb mariadb
soundfile
sounddevice
reportlab