From c68410c070ee09b2d481d3e167cd70689fffcabc Mon Sep 17 00:00:00 2001 From: Sven Carstensen Date: Thu, 16 Jul 2026 14:09:21 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Steuernummer=20und=20USt-IdNr.=20als=20?= =?UTF-8?q?Pflichtfelder=20f=C3=BCr=20Kunden=20und=20Profil-Rechnungsdaten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .../de/assecutor/votianlt/model/Customer.java | 6 ++++ .../votianlt/pages/view/AddCustomerView.java | 32 +++++++++++++++++-- .../votianlt/pages/view/EditCustomerView.java | 13 ++++++++ .../votianlt/pages/view/EditProfileView.java | 20 ++++++++++-- .../src/main/resources/messages_de.properties | 2 ++ .../src/main/resources/messages_ee.properties | 2 ++ .../src/main/resources/messages_en.properties | 2 ++ .../src/main/resources/messages_es.properties | 2 ++ .../src/main/resources/messages_fr.properties | 2 ++ .../src/main/resources/messages_lt.properties | 2 ++ .../src/main/resources/messages_lv.properties | 2 ++ .../src/main/resources/messages_pl.properties | 2 ++ .../src/main/resources/messages_ru.properties | 2 ++ .../src/main/resources/messages_tr.properties | 2 ++ 14 files changed, 87 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/de/assecutor/votianlt/model/Customer.java b/backend/src/main/java/de/assecutor/votianlt/model/Customer.java index 693af07..0c0c05b 100644 --- a/backend/src/main/java/de/assecutor/votianlt/model/Customer.java +++ b/backend/src/main/java/de/assecutor/votianlt/model/Customer.java @@ -18,6 +18,12 @@ public class Customer { @Field("company_name") private String companyName; + @Field("tax_number") + private String taxNumber; + + @Field("ust_id") + private String ustId; + @Field("firstname") private String firstname; diff --git a/backend/src/main/java/de/assecutor/votianlt/pages/view/AddCustomerView.java b/backend/src/main/java/de/assecutor/votianlt/pages/view/AddCustomerView.java index c1abe2c..167afb5 100644 --- a/backend/src/main/java/de/assecutor/votianlt/pages/view/AddCustomerView.java +++ b/backend/src/main/java/de/assecutor/votianlt/pages/view/AddCustomerView.java @@ -28,6 +28,8 @@ public class AddCustomerView extends Main implements HasDynamicTitle { private final AddCustomerService addCustomerService; TextField companyName; + TextField taxNumber; + TextField ustId; ComboBox title; TextField firstName; TextField lastName; @@ -50,6 +52,19 @@ public class AddCustomerView extends Main implements HasDynamicTitle { companyName = new TextField(getTranslation("profile.company")); companyName.setWidthFull(); + // Steuernummer (Pflichtfeld) + taxNumber = new TextField(getTranslation("profile.billing.taxnumber")); + taxNumber.setRequiredIndicatorVisible(true); + taxNumber.setWidthFull(); + taxNumber.addBlurListener(e -> validateField(taxNumber)); + + // USt-IdNr. (Pflichtfeld) + ustId = new TextField(getTranslation("profile.billing.ustid")); + ustId.setRequiredIndicatorVisible(true); + ustId.setPlaceholder("DE123456789"); + ustId.setWidthFull(); + ustId.addBlurListener(e -> validateField(ustId)); + // Anrede (Dropdown) title = new ComboBox<>(getTranslation("addjob.address.salutation")); title.setItems(getTranslation("addjob.salutation.mr"), getTranslation("addjob.salutation.ms"), @@ -126,6 +141,10 @@ public class AddCustomerView extends Main implements HasDynamicTitle { // Felder hinzufügen (einzeln pro Zeile, außer Straße/Hausnr und PLZ/Ort) formLayout.add(companyName); + + // Steuernummer und USt-IdNr. nebeneinander + formLayout.add(taxNumber, ustId); + formLayout.add(title); formLayout.add(firstName); formLayout.add(lastName); @@ -162,6 +181,12 @@ public class AddCustomerView extends Main implements HasDynamicTitle { private void configureBinder() { binder.forField(companyName).bind(Customer::getCompanyName, Customer::setCompanyName); + binder.forField(taxNumber).asRequired(getTranslation("profile.validation.taxnumber.required")) + .bind(Customer::getTaxNumber, Customer::setTaxNumber); + + binder.forField(ustId).asRequired(getTranslation("profile.validation.ustid.required")).bind(Customer::getUstId, + Customer::setUstId); + binder.forField(title).bind(Customer::getTitle, Customer::setTitle); binder.forField(firstName).asRequired(getTranslation("profile.validation.firstname.required")) @@ -260,6 +285,8 @@ public class AddCustomerView extends Main implements HasDynamicTitle { } private boolean validateAllFields() { + validateField(taxNumber); + validateField(ustId); validateField(firstName); validateField(lastName); validateField(telephone); @@ -269,8 +296,9 @@ public class AddCustomerView extends Main implements HasDynamicTitle { validateField(city); validateEmail(); - return !firstName.isInvalid() && !lastName.isInvalid() && !telephone.isInvalid() && !mail.isInvalid() - && !street.isInvalid() && !houseNumber.isInvalid() && !zip.isInvalid() && !city.isInvalid(); + return !taxNumber.isInvalid() && !ustId.isInvalid() && !firstName.isInvalid() && !lastName.isInvalid() + && !telephone.isInvalid() && !mail.isInvalid() && !street.isInvalid() && !houseNumber.isInvalid() + && !zip.isInvalid() && !city.isInvalid(); } @Override diff --git a/backend/src/main/java/de/assecutor/votianlt/pages/view/EditCustomerView.java b/backend/src/main/java/de/assecutor/votianlt/pages/view/EditCustomerView.java index f07f0c0..463d5b0 100644 --- a/backend/src/main/java/de/assecutor/votianlt/pages/view/EditCustomerView.java +++ b/backend/src/main/java/de/assecutor/votianlt/pages/view/EditCustomerView.java @@ -36,6 +36,8 @@ public class EditCustomerView extends VerticalLayout implements HasUrlParameter< // Form fields - labels set in constructor via setLabel() private final TextField titleField = new TextField(); private final TextField companyNameField = new TextField(); + private final TextField taxNumberField = new TextField(); + private final TextField ustIdField = new TextField(); private final TextField firstnameField = new TextField(); private final TextField lastNameField = new TextField(); private final TextField telephoneField = new TextField(); @@ -61,6 +63,11 @@ public class EditCustomerView extends VerticalLayout implements HasUrlParameter< // Set field labels via i18n titleField.setLabel(getTranslation("addjob.address.salutation")); companyNameField.setLabel(getTranslation("profile.company")); + taxNumberField.setLabel(getTranslation("profile.billing.taxnumber")); + taxNumberField.setRequiredIndicatorVisible(true); + ustIdField.setLabel(getTranslation("profile.billing.ustid")); + ustIdField.setRequiredIndicatorVisible(true); + ustIdField.setPlaceholder("DE123456789"); firstnameField.setLabel(getTranslation("profile.firstname")); lastNameField.setLabel(getTranslation("profile.lastname")); telephoneField.setLabel(getTranslation("profile.phone")); @@ -95,6 +102,8 @@ public class EditCustomerView extends VerticalLayout implements HasUrlParameter< // Add fields to form - all fields in single column formLayout.add(titleField); formLayout.add(companyNameField); + formLayout.add(taxNumberField); + formLayout.add(ustIdField); formLayout.add(firstnameField); formLayout.add(lastNameField); formLayout.add(telephoneField); @@ -134,6 +143,10 @@ public class EditCustomerView extends VerticalLayout implements HasUrlParameter< private void setupBinder() { binder.forField(titleField).bind(Customer::getTitle, Customer::setTitle); binder.forField(companyNameField).bind(Customer::getCompanyName, Customer::setCompanyName); + binder.forField(taxNumberField).asRequired(getTranslation("profile.validation.taxnumber.required")) + .bind(Customer::getTaxNumber, Customer::setTaxNumber); + binder.forField(ustIdField).asRequired(getTranslation("profile.validation.ustid.required")) + .bind(Customer::getUstId, Customer::setUstId); binder.forField(firstnameField).bind(Customer::getFirstname, Customer::setFirstname); binder.forField(lastNameField).bind(Customer::getLastName, Customer::setLastName); binder.forField(telephoneField).bind(Customer::getTelephone, Customer::setTelephone); diff --git a/backend/src/main/java/de/assecutor/votianlt/pages/view/EditProfileView.java b/backend/src/main/java/de/assecutor/votianlt/pages/view/EditProfileView.java index 6d421e4..d69199c 100644 --- a/backend/src/main/java/de/assecutor/votianlt/pages/view/EditProfileView.java +++ b/backend/src/main/java/de/assecutor/votianlt/pages/view/EditProfileView.java @@ -376,9 +376,17 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle // ZUGFeRD-E-Rechnung (Absender-USt-IdNr./Steuernummer, IBAN) ustIdField.setLabel(getTranslation("profile.billing.ustid")); ustIdField.setPlaceholder("DE123456789"); - ustIdField.addBlurListener(e -> saveInvoiceData()); + ustIdField.setRequiredIndicatorVisible(true); + ustIdField.addBlurListener(e -> { + validateField(ustIdField, getTranslation("profile.validation.ustid.required")); + saveInvoiceData(); + }); taxNumberField.setLabel(getTranslation("profile.billing.taxnumber")); - taxNumberField.addBlurListener(e -> saveInvoiceData()); + taxNumberField.setRequiredIndicatorVisible(true); + taxNumberField.addBlurListener(e -> { + validateField(taxNumberField, getTranslation("profile.validation.taxnumber.required")); + saveInvoiceData(); + }); bankNameField.setLabel(getTranslation("profile.billing.bankname")); bankNameField.addBlurListener(e -> saveInvoiceData()); ibanField.setLabel(getTranslation("profile.billing.iban")); @@ -639,6 +647,14 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle boolean isValid = validateAllProfileFields(companyField, firstnameField, lastnameField, phoneField, emailField, streetField, houseNumberField, zipField, cityField); + // Steuernummer und USt-IdNr. sind Pflicht, sobald die Rechnungslegung + // aktiviert ist + if (billingEnabled.getValue()) { + validateField(ustIdField, getTranslation("profile.validation.ustid.required")); + validateField(taxNumberField, getTranslation("profile.validation.taxnumber.required")); + isValid = isValid && !ustIdField.isInvalid() && !taxNumberField.isInvalid(); + } + if (!isValid) { Notification.show(getTranslation("profile.validation.required.fill"), 3000, Notification.Position.MIDDLE); diff --git a/backend/src/main/resources/messages_de.properties b/backend/src/main/resources/messages_de.properties index 9fc4edf..3cab678 100644 --- a/backend/src/main/resources/messages_de.properties +++ b/backend/src/main/resources/messages_de.properties @@ -84,6 +84,8 @@ profile.validation.street.required=Straße ist erforderlich profile.validation.housenr.required=Hausnummer ist erforderlich profile.validation.zip.required=Postleitzahl ist erforderlich profile.validation.city.required=Stadt ist erforderlich +profile.validation.taxnumber.required=Steuernummer ist erforderlich +profile.validation.ustid.required=USt-IdNr. ist erforderlich profile.validation.firstname.required=Vorname ist erforderlich profile.validation.lastname.required=Nachname ist erforderlich profile.validation.phone.required=Telefonnummer ist erforderlich diff --git a/backend/src/main/resources/messages_ee.properties b/backend/src/main/resources/messages_ee.properties index 0d81fac..1876de0 100644 --- a/backend/src/main/resources/messages_ee.properties +++ b/backend/src/main/resources/messages_ee.properties @@ -73,6 +73,8 @@ profile.validation.street.required=T\u00e4nav on kohustuslik profile.validation.housenr.required=Majanumber on kohustuslik profile.validation.zip.required=Postiindeks on kohustuslik profile.validation.city.required=Linn on kohustuslik +profile.validation.taxnumber.required=Maksunumber on kohustuslik +profile.validation.ustid.required=KMKR nr on kohustuslik profile.validation.firstname.required=Eesnimi on kohustuslik profile.validation.lastname.required=Perekonnanimi on kohustuslik profile.validation.phone.required=Telefoninumber on kohustuslik diff --git a/backend/src/main/resources/messages_en.properties b/backend/src/main/resources/messages_en.properties index 12cc5cd..0f393d3 100644 --- a/backend/src/main/resources/messages_en.properties +++ b/backend/src/main/resources/messages_en.properties @@ -84,6 +84,8 @@ profile.validation.street.required=Street is required profile.validation.housenr.required=House number is required profile.validation.zip.required=Postal code is required profile.validation.city.required=City is required +profile.validation.taxnumber.required=Tax number is required +profile.validation.ustid.required=VAT ID is required profile.validation.firstname.required=First name is required profile.validation.lastname.required=Last name is required profile.validation.phone.required=Phone number is required diff --git a/backend/src/main/resources/messages_es.properties b/backend/src/main/resources/messages_es.properties index ce5f166..7dbf33c 100644 --- a/backend/src/main/resources/messages_es.properties +++ b/backend/src/main/resources/messages_es.properties @@ -83,6 +83,8 @@ profile.validation.street.required=Calle es obligatorio profile.validation.housenr.required=N\u00famero de casa es obligatorio profile.validation.zip.required=C\u00f3digo postal es obligatorio profile.validation.city.required=Ciudad es obligatorio +profile.validation.taxnumber.required=Número fiscal es obligatorio +profile.validation.ustid.required=NIF-IVA es obligatorio profile.validation.firstname.required=Nombre es obligatorio profile.validation.lastname.required=Apellido es obligatorio profile.validation.phone.required=N\u00famero de tel\u00e9fono es obligatorio diff --git a/backend/src/main/resources/messages_fr.properties b/backend/src/main/resources/messages_fr.properties index e156c13..b0b1ec0 100644 --- a/backend/src/main/resources/messages_fr.properties +++ b/backend/src/main/resources/messages_fr.properties @@ -83,6 +83,8 @@ profile.validation.street.required=La rue est obligatoire profile.validation.housenr.required=Le num\u00e9ro est obligatoire profile.validation.zip.required=Le code postal est obligatoire profile.validation.city.required=La ville est obligatoire +profile.validation.taxnumber.required=Le numéro fiscal est obligatoire +profile.validation.ustid.required=Le n° TVA intracommunautaire est obligatoire profile.validation.firstname.required=Le pr\u00e9nom est obligatoire profile.validation.lastname.required=Le nom est obligatoire profile.validation.phone.required=Le num\u00e9ro de t\u00e9l\u00e9phone est obligatoire diff --git a/backend/src/main/resources/messages_lt.properties b/backend/src/main/resources/messages_lt.properties index dc43c34..24c8647 100644 --- a/backend/src/main/resources/messages_lt.properties +++ b/backend/src/main/resources/messages_lt.properties @@ -83,6 +83,8 @@ profile.validation.street.required=Gatvė yra privaloma profile.validation.housenr.required=Namo numeris yra privalomas profile.validation.zip.required=Pašto kodas yra privalomas profile.validation.city.required=Miestas yra privalomas +profile.validation.taxnumber.required=Mokesčių mokėtojo numeris yra privalomas +profile.validation.ustid.required=PVM mokėtojo kodas yra privalomas profile.validation.firstname.required=Vardas yra privalomas profile.validation.lastname.required=Pavardė yra privaloma profile.validation.phone.required=Telefono numeris yra privalomas diff --git a/backend/src/main/resources/messages_lv.properties b/backend/src/main/resources/messages_lv.properties index c997e81..9ac82c9 100644 --- a/backend/src/main/resources/messages_lv.properties +++ b/backend/src/main/resources/messages_lv.properties @@ -83,6 +83,8 @@ profile.validation.street.required=Iela ir obligāta profile.validation.housenr.required=Mājas numurs ir obligāts profile.validation.zip.required=Pasta indekss ir obligāts profile.validation.city.required=Pilsēta ir obligāta +profile.validation.taxnumber.required=Nodokļu maksātāja numurs ir obligāts +profile.validation.ustid.required=PVN numurs ir obligāts profile.validation.firstname.required=Vārds ir obligāts profile.validation.lastname.required=Uzvārds ir obligāts profile.validation.phone.required=Tālruņa numurs ir obligāts diff --git a/backend/src/main/resources/messages_pl.properties b/backend/src/main/resources/messages_pl.properties index 172bdec..0cfb45b 100644 --- a/backend/src/main/resources/messages_pl.properties +++ b/backend/src/main/resources/messages_pl.properties @@ -83,6 +83,8 @@ profile.validation.street.required=Ulica jest wymagana profile.validation.housenr.required=Numer domu jest wymagany profile.validation.zip.required=Kod pocztowy jest wymagany profile.validation.city.required=Miasto jest wymagane +profile.validation.taxnumber.required=Numer podatkowy jest wymagany +profile.validation.ustid.required=NIP UE jest wymagany profile.validation.firstname.required=Imi\u0119 jest wymagane profile.validation.lastname.required=Nazwisko jest wymagane profile.validation.phone.required=Numer telefonu jest wymagany diff --git a/backend/src/main/resources/messages_ru.properties b/backend/src/main/resources/messages_ru.properties index 6980975..4b16624 100644 --- a/backend/src/main/resources/messages_ru.properties +++ b/backend/src/main/resources/messages_ru.properties @@ -83,6 +83,8 @@ profile.validation.street.required=Улица обязательна profile.validation.housenr.required=Номер дома обязателен profile.validation.zip.required=Почтовый индекс обязателен profile.validation.city.required=Город обязателен +profile.validation.taxnumber.required=Налоговый номер обязателен +profile.validation.ustid.required=Идентификатор плательщика НДС обязателен profile.validation.firstname.required=Имя обязательно profile.validation.lastname.required=Фамилия обязательна profile.validation.phone.required=Номер телефона обязателен diff --git a/backend/src/main/resources/messages_tr.properties b/backend/src/main/resources/messages_tr.properties index 5ba9b85..e339c9c 100644 --- a/backend/src/main/resources/messages_tr.properties +++ b/backend/src/main/resources/messages_tr.properties @@ -83,6 +83,8 @@ profile.validation.street.required=Sokak gereklidir profile.validation.housenr.required=Kap\u0131 numaras\u0131 gereklidir profile.validation.zip.required=Posta kodu gereklidir profile.validation.city.required=\u015eehir gereklidir +profile.validation.taxnumber.required=Vergi numarası gereklidir +profile.validation.ustid.required=KDV kimlik no gereklidir profile.validation.firstname.required=Ad gereklidir profile.validation.lastname.required=Soyad gereklidir profile.validation.phone.required=Telefon numaras\u0131 gereklidir