Telefon und Webseite des Rechnungsstellers: Adressbuch-Feld, Formularfelder, Belegung von masterdata.phone/website
- Adressbuch: neues Feld "Webseite" pro Unternehmen - Rechnungsmaske: Telefon und Webseite beim Rechnungssteller manuell erfassbar, Vorbelegung aus dem Adressbuch - masterdata.phone/masterdata.website werden aus den Formularfeldern belegt, mit Adressbuch-Fallback (bisher immer leer) - Webseite wird in Vorbelegungen mitgespeichert, Telefon fließt über Party.phone in die ZUGFeRD-Daten Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,7 @@ public class Address {
|
||||
private String vatId;
|
||||
private String email;
|
||||
private String phone;
|
||||
private String website;
|
||||
|
||||
// Bankverbindung (v. a. für Rechnungssteller relevant)
|
||||
private String bankName;
|
||||
@@ -119,6 +120,14 @@ public class Address {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getWebsite() {
|
||||
return website;
|
||||
}
|
||||
|
||||
public void setWebsite(String website) {
|
||||
this.website = website;
|
||||
}
|
||||
|
||||
public String getBankName() {
|
||||
return bankName;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ public record InvoiceDraft(
|
||||
String buyerReference,
|
||||
String iban,
|
||||
String bic,
|
||||
String website,
|
||||
InvoiceMetadata.Party sender,
|
||||
InvoiceMetadata.Party recipient,
|
||||
List<InvoiceMetadata.LineItem> items,
|
||||
|
||||
@@ -159,6 +159,9 @@ public class AddressBookView extends VerticalLayout {
|
||||
});
|
||||
TextField phone = new TextField("Telefon");
|
||||
phone.setValue(target.getPhone() != null ? target.getPhone() : "");
|
||||
TextField website = new TextField("Webseite");
|
||||
website.setValue(target.getWebsite() != null ? target.getWebsite() : "");
|
||||
website.setHelperText("z. B. www.assecutor.de");
|
||||
|
||||
// Bankverbindung (optional)
|
||||
TextField bankName = new TextField("Bank");
|
||||
@@ -170,7 +173,7 @@ public class AddressBookView extends VerticalLayout {
|
||||
bic.setValue(target.getBic() != null ? target.getBic() : "");
|
||||
|
||||
FormLayout form = new FormLayout(type, name, street, zip, city, countryCode, vatId, email, phone,
|
||||
bankName, iban, bic);
|
||||
website, bankName, iban, bic);
|
||||
form.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1), new FormLayout.ResponsiveStep("500px", 2));
|
||||
form.setWidth("560px");
|
||||
dialog.add(form);
|
||||
@@ -231,6 +234,7 @@ public class AddressBookView extends VerticalLayout {
|
||||
target.setVatId(vatId.getValue().isBlank() ? "" : VatIdValidator.normalize(vatId.getValue()));
|
||||
target.setEmail(email.getValue().trim());
|
||||
target.setPhone(phone.getValue().trim());
|
||||
target.setWebsite(website.getValue().trim());
|
||||
target.setBankName(bankName.getValue().trim());
|
||||
target.setIban(iban.getValue().isBlank() ? "" : IbanValidator.normalize(iban.getValue()));
|
||||
target.setBic(bic.getValue().trim().toUpperCase());
|
||||
|
||||
@@ -379,6 +379,7 @@ public class MainView extends VerticalLayout {
|
||||
"",
|
||||
sender.ibanNormalized(),
|
||||
sender.bicNormalized(),
|
||||
sender.websiteValue(),
|
||||
sender.toParty(), recipient.toParty(),
|
||||
List.copyOf(lineItems),
|
||||
LocalDateTime.now());
|
||||
@@ -410,6 +411,8 @@ public class MainView extends VerticalLayout {
|
||||
currency.setValue(nullToEmpty(draft.currency()));
|
||||
paymentTerms.setValue(nullToEmpty(draft.paymentTerms()));
|
||||
applyParty(sender, draft.sender());
|
||||
sender.prefillContact(draft.sender() != null ? nullToEmpty(draft.sender().phone()) : "",
|
||||
nullToEmpty(draft.website()));
|
||||
sender.prefillBank(nullToEmpty(draft.iban()), nullToEmpty(draft.bic()));
|
||||
applyParty(recipient, draft.recipient());
|
||||
lineItems.clear();
|
||||
@@ -447,6 +450,7 @@ public class MainView extends VerticalLayout {
|
||||
nullToEmpty(address.getZip()), nullToEmpty(address.getCity()),
|
||||
nullToEmpty(address.getCountryCode()), nullToEmpty(address.getVatId()),
|
||||
nullToEmpty(address.getEmail()));
|
||||
form.prefillContact(nullToEmpty(address.getPhone()), nullToEmpty(address.getWebsite()));
|
||||
form.prefillBank(nullToEmpty(address.getIban()), nullToEmpty(address.getBic()));
|
||||
}
|
||||
});
|
||||
@@ -545,6 +549,7 @@ public class MainView extends VerticalLayout {
|
||||
"",
|
||||
sender.ibanNormalized(),
|
||||
sender.bicNormalized(),
|
||||
sender.websiteValue(),
|
||||
sender.toParty(), recipient.toParty(),
|
||||
List.copyOf(lineItems),
|
||||
null);
|
||||
@@ -661,12 +666,20 @@ public class MainView extends VerticalLayout {
|
||||
private Map<String, String> buildTemplateVariables(InvoiceMetadata metadata) {
|
||||
Map<String, String> variables = new LinkedHashMap<>();
|
||||
InvoiceMetadata.Party senderParty = metadata.sender();
|
||||
// Telefon und Webseite kommen aus den Formularfeldern des
|
||||
// Rechnungsstellers; sind sie leer (z. B. alte Vorbelegung), springt
|
||||
// der Adressbuch-Eintrag des Rechnungsstellers ein.
|
||||
Optional<Address> senderAddress = findSenderAddress(senderParty.name());
|
||||
String phone = !senderParty.phone().isBlank() ? senderParty.phone()
|
||||
: senderAddress.map(address -> nullToEmpty(address.getPhone())).orElse("");
|
||||
String website = !sender.websiteValue().isBlank() ? sender.websiteValue()
|
||||
: senderAddress.map(address -> nullToEmpty(address.getWebsite())).orElse("");
|
||||
variables.put("masterdata.company_name", senderParty.name());
|
||||
variables.put("masterdata.street", senderParty.street());
|
||||
variables.put("masterdata.city", senderParty.zip() + " " + senderParty.city());
|
||||
variables.put("masterdata.phone", senderParty.phone());
|
||||
variables.put("masterdata.phone", phone);
|
||||
variables.put("masterdata.email", senderParty.email());
|
||||
variables.put("masterdata.website", "");
|
||||
variables.put("masterdata.website", website);
|
||||
variables.put("masterdata.sender_line",
|
||||
senderParty.name() + " · " + senderParty.street() + " · " + senderParty.zip() + " " + senderParty.city());
|
||||
variables.put("masterdata.payment_terms", metadata.paymentTerms());
|
||||
@@ -697,6 +710,22 @@ public class MainView extends VerticalLayout {
|
||||
return variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return der Adressbuch-Eintrag des Rechnungsstellers: die Auswahl in
|
||||
* "Aus dem Adressbuch übernehmen", sonst der Namenstreffer unter
|
||||
* den Rechnungssteller-Adressen (z. B. nach Laden einer Vorbelegung).
|
||||
*/
|
||||
private Optional<Address> findSenderAddress(String senderName) {
|
||||
Address selected = senderAddressSelect.getValue();
|
||||
if (selected != null) {
|
||||
return Optional.of(selected);
|
||||
}
|
||||
String normalized = senderName == null ? "" : senderName.trim();
|
||||
return addressRepository.findByType(AddressType.RECHNUNGSSTELLER).stream()
|
||||
.filter(address -> normalized.equalsIgnoreCase(nullToEmpty(address.getName()).trim()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/** Wandelt das Quell-PDF in die ZUGFeRD-E-Rechnung um und bietet das ZIP zum Download an. */
|
||||
private void convertAndOfferDownload(byte[] sourcePdf) {
|
||||
try {
|
||||
@@ -823,6 +852,10 @@ public class MainView extends VerticalLayout {
|
||||
private final TextField vatId = new TextField("USt-IdNr.");
|
||||
private final EmailField email = new EmailField("E-Mail");
|
||||
|
||||
// Kontaktangaben; nur beim Rechnungssteller sichtbar und optional
|
||||
private final TextField phone = new TextField("Telefon");
|
||||
private final TextField website = new TextField("Webseite");
|
||||
|
||||
// Bankverbindung; nur beim Rechnungssteller sichtbar und Pflicht
|
||||
private final TextField iban = new TextField("IBAN");
|
||||
private final TextField bic = new TextField("BIC");
|
||||
@@ -849,11 +882,12 @@ public class MainView extends VerticalLayout {
|
||||
email.addValueChangeListener(event -> checkEmail());
|
||||
add(name, street, zip, city, countryCode, vatId, email);
|
||||
if (vatRequired) {
|
||||
website.setHelperText("z. B. www.assecutor.de");
|
||||
iban.setRequired(true);
|
||||
iban.setHelperText("Für die Zahlungsangaben (BG-16)");
|
||||
bic.setRequired(true);
|
||||
bic.setHelperText("8 oder 11 Stellen, z. B. NOLADE21RZB");
|
||||
add(iban, bic);
|
||||
add(phone, website, iban, bic);
|
||||
}
|
||||
setResponsiveSteps(new ResponsiveStep("0", 1), new ResponsiveStep("600px", 3));
|
||||
}
|
||||
@@ -864,6 +898,16 @@ public class MainView extends VerticalLayout {
|
||||
bic.setValue(bicValue);
|
||||
}
|
||||
|
||||
/** Belegt Telefon und Webseite vor, z. B. aus dem Adressbuch. */
|
||||
void prefillContact(String phoneValue, String websiteValue) {
|
||||
phone.setValue(phoneValue);
|
||||
website.setValue(websiteValue);
|
||||
}
|
||||
|
||||
String websiteValue() {
|
||||
return website.getValue().trim();
|
||||
}
|
||||
|
||||
/** IBAN ohne Leerzeichen in Großschreibung. */
|
||||
String ibanNormalized() {
|
||||
return iban.getValue().replaceAll("\\s", "").toUpperCase();
|
||||
@@ -906,6 +950,8 @@ public class MainView extends VerticalLayout {
|
||||
countryCode.addValueChangeListener(event -> listener.run());
|
||||
vatId.addValueChangeListener(event -> listener.run());
|
||||
email.addValueChangeListener(event -> listener.run());
|
||||
phone.addValueChangeListener(event -> listener.run());
|
||||
website.addValueChangeListener(event -> listener.run());
|
||||
iban.addValueChangeListener(event -> listener.run());
|
||||
bic.addValueChangeListener(event -> listener.run());
|
||||
}
|
||||
@@ -913,6 +959,7 @@ public class MainView extends VerticalLayout {
|
||||
/** Leert alle Felder; das Land behält den Standardwert "DE". */
|
||||
void clearFields() {
|
||||
prefill("", "", "", "", "DE", "", "");
|
||||
prefillContact("", "");
|
||||
prefillBank("", "");
|
||||
name.setInvalid(false);
|
||||
street.setInvalid(false);
|
||||
@@ -995,7 +1042,7 @@ public class MainView extends VerticalLayout {
|
||||
countryCode.getValue().trim().toUpperCase(),
|
||||
vatId.isEmpty() ? "" : VatIdValidator.normalize(vatId.getValue()),
|
||||
email.getValue().trim(),
|
||||
""
|
||||
phone.getValue().trim()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user