feat: Steuernummer und USt-IdNr. als Pflichtfelder für Kunden und Profil-Rechnungsdaten

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 14:09:21 +02:00
co-authored by Claude Fable 5
parent d146d2f319
commit c68410c070
14 changed files with 87 additions and 4 deletions
@@ -18,6 +18,12 @@ public class Customer {
@Field("company_name") @Field("company_name")
private String companyName; private String companyName;
@Field("tax_number")
private String taxNumber;
@Field("ust_id")
private String ustId;
@Field("firstname") @Field("firstname")
private String firstname; private String firstname;
@@ -28,6 +28,8 @@ public class AddCustomerView extends Main implements HasDynamicTitle {
private final AddCustomerService addCustomerService; private final AddCustomerService addCustomerService;
TextField companyName; TextField companyName;
TextField taxNumber;
TextField ustId;
ComboBox<String> title; ComboBox<String> title;
TextField firstName; TextField firstName;
TextField lastName; TextField lastName;
@@ -50,6 +52,19 @@ public class AddCustomerView extends Main implements HasDynamicTitle {
companyName = new TextField(getTranslation("profile.company")); companyName = new TextField(getTranslation("profile.company"));
companyName.setWidthFull(); 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) // Anrede (Dropdown)
title = new ComboBox<>(getTranslation("addjob.address.salutation")); title = new ComboBox<>(getTranslation("addjob.address.salutation"));
title.setItems(getTranslation("addjob.salutation.mr"), getTranslation("addjob.salutation.ms"), 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) // Felder hinzufügen (einzeln pro Zeile, außer Straße/Hausnr und PLZ/Ort)
formLayout.add(companyName); formLayout.add(companyName);
// Steuernummer und USt-IdNr. nebeneinander
formLayout.add(taxNumber, ustId);
formLayout.add(title); formLayout.add(title);
formLayout.add(firstName); formLayout.add(firstName);
formLayout.add(lastName); formLayout.add(lastName);
@@ -162,6 +181,12 @@ public class AddCustomerView extends Main implements HasDynamicTitle {
private void configureBinder() { private void configureBinder() {
binder.forField(companyName).bind(Customer::getCompanyName, Customer::setCompanyName); 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(title).bind(Customer::getTitle, Customer::setTitle);
binder.forField(firstName).asRequired(getTranslation("profile.validation.firstname.required")) binder.forField(firstName).asRequired(getTranslation("profile.validation.firstname.required"))
@@ -260,6 +285,8 @@ public class AddCustomerView extends Main implements HasDynamicTitle {
} }
private boolean validateAllFields() { private boolean validateAllFields() {
validateField(taxNumber);
validateField(ustId);
validateField(firstName); validateField(firstName);
validateField(lastName); validateField(lastName);
validateField(telephone); validateField(telephone);
@@ -269,8 +296,9 @@ public class AddCustomerView extends Main implements HasDynamicTitle {
validateField(city); validateField(city);
validateEmail(); validateEmail();
return !firstName.isInvalid() && !lastName.isInvalid() && !telephone.isInvalid() && !mail.isInvalid() return !taxNumber.isInvalid() && !ustId.isInvalid() && !firstName.isInvalid() && !lastName.isInvalid()
&& !street.isInvalid() && !houseNumber.isInvalid() && !zip.isInvalid() && !city.isInvalid(); && !telephone.isInvalid() && !mail.isInvalid() && !street.isInvalid() && !houseNumber.isInvalid()
&& !zip.isInvalid() && !city.isInvalid();
} }
@Override @Override
@@ -36,6 +36,8 @@ public class EditCustomerView extends VerticalLayout implements HasUrlParameter<
// Form fields - labels set in constructor via setLabel() // Form fields - labels set in constructor via setLabel()
private final TextField titleField = new TextField(); private final TextField titleField = new TextField();
private final TextField companyNameField = 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 firstnameField = new TextField();
private final TextField lastNameField = new TextField(); private final TextField lastNameField = new TextField();
private final TextField telephoneField = new TextField(); private final TextField telephoneField = new TextField();
@@ -61,6 +63,11 @@ public class EditCustomerView extends VerticalLayout implements HasUrlParameter<
// Set field labels via i18n // Set field labels via i18n
titleField.setLabel(getTranslation("addjob.address.salutation")); titleField.setLabel(getTranslation("addjob.address.salutation"));
companyNameField.setLabel(getTranslation("profile.company")); 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")); firstnameField.setLabel(getTranslation("profile.firstname"));
lastNameField.setLabel(getTranslation("profile.lastname")); lastNameField.setLabel(getTranslation("profile.lastname"));
telephoneField.setLabel(getTranslation("profile.phone")); 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 // Add fields to form - all fields in single column
formLayout.add(titleField); formLayout.add(titleField);
formLayout.add(companyNameField); formLayout.add(companyNameField);
formLayout.add(taxNumberField);
formLayout.add(ustIdField);
formLayout.add(firstnameField); formLayout.add(firstnameField);
formLayout.add(lastNameField); formLayout.add(lastNameField);
formLayout.add(telephoneField); formLayout.add(telephoneField);
@@ -134,6 +143,10 @@ public class EditCustomerView extends VerticalLayout implements HasUrlParameter<
private void setupBinder() { private void setupBinder() {
binder.forField(titleField).bind(Customer::getTitle, Customer::setTitle); binder.forField(titleField).bind(Customer::getTitle, Customer::setTitle);
binder.forField(companyNameField).bind(Customer::getCompanyName, Customer::setCompanyName); 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(firstnameField).bind(Customer::getFirstname, Customer::setFirstname);
binder.forField(lastNameField).bind(Customer::getLastName, Customer::setLastName); binder.forField(lastNameField).bind(Customer::getLastName, Customer::setLastName);
binder.forField(telephoneField).bind(Customer::getTelephone, Customer::setTelephone); binder.forField(telephoneField).bind(Customer::getTelephone, Customer::setTelephone);
@@ -376,9 +376,17 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle
// ZUGFeRD-E-Rechnung (Absender-USt-IdNr./Steuernummer, IBAN) // ZUGFeRD-E-Rechnung (Absender-USt-IdNr./Steuernummer, IBAN)
ustIdField.setLabel(getTranslation("profile.billing.ustid")); ustIdField.setLabel(getTranslation("profile.billing.ustid"));
ustIdField.setPlaceholder("DE123456789"); 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.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.setLabel(getTranslation("profile.billing.bankname"));
bankNameField.addBlurListener(e -> saveInvoiceData()); bankNameField.addBlurListener(e -> saveInvoiceData());
ibanField.setLabel(getTranslation("profile.billing.iban")); ibanField.setLabel(getTranslation("profile.billing.iban"));
@@ -639,6 +647,14 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle
boolean isValid = validateAllProfileFields(companyField, firstnameField, lastnameField, phoneField, boolean isValid = validateAllProfileFields(companyField, firstnameField, lastnameField, phoneField,
emailField, streetField, houseNumberField, zipField, cityField); 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) { if (!isValid) {
Notification.show(getTranslation("profile.validation.required.fill"), 3000, Notification.show(getTranslation("profile.validation.required.fill"), 3000,
Notification.Position.MIDDLE); Notification.Position.MIDDLE);
@@ -84,6 +84,8 @@ profile.validation.street.required=Straße ist erforderlich
profile.validation.housenr.required=Hausnummer ist erforderlich profile.validation.housenr.required=Hausnummer ist erforderlich
profile.validation.zip.required=Postleitzahl ist erforderlich profile.validation.zip.required=Postleitzahl ist erforderlich
profile.validation.city.required=Stadt 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.firstname.required=Vorname ist erforderlich
profile.validation.lastname.required=Nachname ist erforderlich profile.validation.lastname.required=Nachname ist erforderlich
profile.validation.phone.required=Telefonnummer ist erforderlich profile.validation.phone.required=Telefonnummer ist erforderlich
@@ -73,6 +73,8 @@ profile.validation.street.required=T\u00e4nav on kohustuslik
profile.validation.housenr.required=Majanumber on kohustuslik profile.validation.housenr.required=Majanumber on kohustuslik
profile.validation.zip.required=Postiindeks on kohustuslik profile.validation.zip.required=Postiindeks on kohustuslik
profile.validation.city.required=Linn 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.firstname.required=Eesnimi on kohustuslik
profile.validation.lastname.required=Perekonnanimi on kohustuslik profile.validation.lastname.required=Perekonnanimi on kohustuslik
profile.validation.phone.required=Telefoninumber on kohustuslik profile.validation.phone.required=Telefoninumber on kohustuslik
@@ -84,6 +84,8 @@ profile.validation.street.required=Street is required
profile.validation.housenr.required=House number is required profile.validation.housenr.required=House number is required
profile.validation.zip.required=Postal code is required profile.validation.zip.required=Postal code is required
profile.validation.city.required=City 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.firstname.required=First name is required
profile.validation.lastname.required=Last name is required profile.validation.lastname.required=Last name is required
profile.validation.phone.required=Phone number is required profile.validation.phone.required=Phone number is required
@@ -83,6 +83,8 @@ profile.validation.street.required=Calle es obligatorio
profile.validation.housenr.required=N\u00famero de casa es obligatorio profile.validation.housenr.required=N\u00famero de casa es obligatorio
profile.validation.zip.required=C\u00f3digo postal es obligatorio profile.validation.zip.required=C\u00f3digo postal es obligatorio
profile.validation.city.required=Ciudad 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.firstname.required=Nombre es obligatorio
profile.validation.lastname.required=Apellido es obligatorio profile.validation.lastname.required=Apellido es obligatorio
profile.validation.phone.required=N\u00famero de tel\u00e9fono es obligatorio profile.validation.phone.required=N\u00famero de tel\u00e9fono es obligatorio
@@ -83,6 +83,8 @@ profile.validation.street.required=La rue est obligatoire
profile.validation.housenr.required=Le num\u00e9ro est obligatoire profile.validation.housenr.required=Le num\u00e9ro est obligatoire
profile.validation.zip.required=Le code postal est obligatoire profile.validation.zip.required=Le code postal est obligatoire
profile.validation.city.required=La ville 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.firstname.required=Le pr\u00e9nom est obligatoire
profile.validation.lastname.required=Le nom est obligatoire profile.validation.lastname.required=Le nom est obligatoire
profile.validation.phone.required=Le num\u00e9ro de t\u00e9l\u00e9phone est obligatoire profile.validation.phone.required=Le num\u00e9ro de t\u00e9l\u00e9phone est obligatoire
@@ -83,6 +83,8 @@ profile.validation.street.required=Gatvė yra privaloma
profile.validation.housenr.required=Namo numeris yra privalomas profile.validation.housenr.required=Namo numeris yra privalomas
profile.validation.zip.required=Pašto kodas yra privalomas profile.validation.zip.required=Pašto kodas yra privalomas
profile.validation.city.required=Miestas 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.firstname.required=Vardas yra privalomas
profile.validation.lastname.required=Pavardė yra privaloma profile.validation.lastname.required=Pavardė yra privaloma
profile.validation.phone.required=Telefono numeris yra privalomas profile.validation.phone.required=Telefono numeris yra privalomas
@@ -83,6 +83,8 @@ profile.validation.street.required=Iela ir obligāta
profile.validation.housenr.required=Mājas numurs ir obligāts profile.validation.housenr.required=Mājas numurs ir obligāts
profile.validation.zip.required=Pasta indekss ir obligāts profile.validation.zip.required=Pasta indekss ir obligāts
profile.validation.city.required=Pilsēta ir obligāta 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.firstname.required=Vārds ir obligāts
profile.validation.lastname.required=Uzvārds ir obligāts profile.validation.lastname.required=Uzvārds ir obligāts
profile.validation.phone.required=Tālruņa numurs ir obligāts profile.validation.phone.required=Tālruņa numurs ir obligāts
@@ -83,6 +83,8 @@ profile.validation.street.required=Ulica jest wymagana
profile.validation.housenr.required=Numer domu jest wymagany profile.validation.housenr.required=Numer domu jest wymagany
profile.validation.zip.required=Kod pocztowy jest wymagany profile.validation.zip.required=Kod pocztowy jest wymagany
profile.validation.city.required=Miasto jest wymagane 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.firstname.required=Imi\u0119 jest wymagane
profile.validation.lastname.required=Nazwisko jest wymagane profile.validation.lastname.required=Nazwisko jest wymagane
profile.validation.phone.required=Numer telefonu jest wymagany profile.validation.phone.required=Numer telefonu jest wymagany
@@ -83,6 +83,8 @@ profile.validation.street.required=Улица обязательна
profile.validation.housenr.required=Номер дома обязателен profile.validation.housenr.required=Номер дома обязателен
profile.validation.zip.required=Почтовый индекс обязателен profile.validation.zip.required=Почтовый индекс обязателен
profile.validation.city.required=Город обязателен profile.validation.city.required=Город обязателен
profile.validation.taxnumber.required=Налоговый номер обязателен
profile.validation.ustid.required=Идентификатор плательщика НДС обязателен
profile.validation.firstname.required=Имя обязательно profile.validation.firstname.required=Имя обязательно
profile.validation.lastname.required=Фамилия обязательна profile.validation.lastname.required=Фамилия обязательна
profile.validation.phone.required=Номер телефона обязателен profile.validation.phone.required=Номер телефона обязателен
@@ -83,6 +83,8 @@ profile.validation.street.required=Sokak gereklidir
profile.validation.housenr.required=Kap\u0131 numaras\u0131 gereklidir profile.validation.housenr.required=Kap\u0131 numaras\u0131 gereklidir
profile.validation.zip.required=Posta kodu gereklidir profile.validation.zip.required=Posta kodu gereklidir
profile.validation.city.required=\u015eehir 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.firstname.required=Ad gereklidir
profile.validation.lastname.required=Soyad gereklidir profile.validation.lastname.required=Soyad gereklidir
profile.validation.phone.required=Telefon numaras\u0131 gereklidir profile.validation.phone.required=Telefon numaras\u0131 gereklidir