From 09e39839cc3abf598cc956ae1ec3c964fdd71f5b Mon Sep 17 00:00:00 2001 From: Sven Carstensen Date: Fri, 19 Sep 2025 21:34:48 +0200 Subject: [PATCH] Erweiterungen --- pom.xml | 31 +++++- .../votianlt/pages/view/PdfTestView.java | 91 ++++++++++++++++- .../service/SystemInvoiceService.java | 79 +++++++++++++-- src/main/resources/templates/vltInvoice.html | 97 +++++++++++++++++++ 4 files changed, 288 insertions(+), 10 deletions(-) create mode 100644 src/main/resources/templates/vltInvoice.html diff --git a/pom.xml b/pom.xml index c64bf6e..e3a0b4a 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,35 @@ 3.0.3 + + + com.itextpdf + itext-core + 8.0.5 + pom + + + + + com.itextpdf + kernel + 8.0.5 + + + + + com.itextpdf + layout + 8.0.5 + + + + + com.itextpdf + html2pdf + 5.0.5 + + @@ -280,4 +309,4 @@ - \ No newline at end of file + diff --git a/src/main/java/de/assecutor/votianlt/pages/view/PdfTestView.java b/src/main/java/de/assecutor/votianlt/pages/view/PdfTestView.java index b82cc43..055574d 100644 --- a/src/main/java/de/assecutor/votianlt/pages/view/PdfTestView.java +++ b/src/main/java/de/assecutor/votianlt/pages/view/PdfTestView.java @@ -2,7 +2,9 @@ package de.assecutor.votianlt.pages.view; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.html.H2; +import com.vaadin.flow.component.html.IFrame; import com.vaadin.flow.component.notification.Notification; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; @@ -19,6 +21,7 @@ import java.io.ByteArrayInputStream; @RolesAllowed("ADMIN") public class PdfTestView extends VerticalLayout { private final SystemInvoiceService systemInvoiceService; + private IFrame pdfViewer; public PdfTestView(SystemInvoiceService systemInvoiceService) { this.systemInvoiceService = systemInvoiceService; @@ -34,7 +37,29 @@ public class PdfTestView extends VerticalLayout { Button generatePdfButton = new Button("Test-Rechnung PDF generieren"); generatePdfButton.addClickListener(e -> generateTestPdf()); - add(generatePdfButton); + Button generateHtmlPdfButton = new Button("PDF aus vltInvoice.html generieren"); + generateHtmlPdfButton.addClickListener(e -> generateHtmlPdf()); + + Button generateTestPdfFromHtmlButton = new Button("Test PDF aus vltInvoice.html erstellen"); + generateTestPdfFromHtmlButton.addClickListener(e -> generateTestPdfFromHtml()); + + Button showPdfInlineButton = new Button("PDF inline anzeigen"); + showPdfInlineButton.addClickListener(e -> showPdfInline()); + + // Create button layout + HorizontalLayout buttonLayout = new HorizontalLayout(); + buttonLayout.add(generatePdfButton, generateHtmlPdfButton, generateTestPdfFromHtmlButton, showPdfInlineButton); + buttonLayout.setSpacing(true); + + // Initialize PDF viewer + pdfViewer = new IFrame(); + pdfViewer.setWidth("100%"); + pdfViewer.setHeight("800px"); + pdfViewer.getStyle().set("border", "1px solid #ccc"); + pdfViewer.setVisible(false); + + add(buttonLayout); + add(pdfViewer); } private void generateTestPdf() { @@ -58,5 +83,67 @@ public class PdfTestView extends VerticalLayout { } } + private void generateHtmlPdf() { + try { + byte[] pdfBytes = systemInvoiceService.generateInvoicePdfFromHtml(); -} \ No newline at end of file + StreamResource resource = new StreamResource("vlt-invoice.pdf", + () -> new ByteArrayInputStream(pdfBytes)); + resource.setContentType("application/pdf"); + + getUI().ifPresent(ui -> { + var registration = ui.getSession().getResourceRegistry().registerResource(resource); + ui.getPage().open(registration.getResourceUri().toString(), "_blank"); + }); + + Notification.show("PDF aus HTML erfolgreich generiert!", 3000, Notification.Position.BOTTOM_CENTER); + } catch (Exception ex) { + Notification.show("Fehler beim Generieren des PDFs aus HTML: " + ex.getMessage(), + 5000, Notification.Position.BOTTOM_CENTER); + } + } + + private void generateTestPdfFromHtml() { + try { + SystemInvoiceData sampleData = systemInvoiceService.createSampleInvoiceData(); + byte[] pdfBytes = systemInvoiceService.generateInvoicePdfFromHtml(); + + StreamResource resource = new StreamResource("test-invoice-from-html.pdf", + () -> new ByteArrayInputStream(pdfBytes)); + resource.setContentType("application/pdf"); + + getUI().ifPresent(ui -> { + var registration = ui.getSession().getResourceRegistry().registerResource(resource); + ui.getPage().open(registration.getResourceUri().toString(), "_blank"); + }); + + Notification.show("Test PDF aus HTML erfolgreich generiert!", 3000, Notification.Position.BOTTOM_CENTER); + } catch (Exception ex) { + Notification.show("Fehler beim Generieren des Test PDFs aus HTML: " + ex.getMessage(), + 5000, Notification.Position.BOTTOM_CENTER); + } + } + + private void showPdfInline() { + try { + SystemInvoiceData sampleData = systemInvoiceService.createSampleInvoiceData(); + byte[] pdfBytes = systemInvoiceService.generateInvoicePdf(sampleData); + + StreamResource resource = new StreamResource("inline-invoice.pdf", + () -> new ByteArrayInputStream(pdfBytes)); + resource.setContentType("application/pdf"); + + getUI().ifPresent(ui -> { + var registration = ui.getSession().getResourceRegistry().registerResource(resource); + pdfViewer.setSrc(registration.getResourceUri().toString()); + pdfViewer.setVisible(true); + }); + + Notification.show("PDF wird inline angezeigt!", 3000, Notification.Position.BOTTOM_CENTER); + } catch (Exception ex) { + Notification.show("Fehler beim Anzeigen des PDFs: " + ex.getMessage(), + 5000, Notification.Position.BOTTOM_CENTER); + } + } + +} diff --git a/src/main/java/de/assecutor/votianlt/service/SystemInvoiceService.java b/src/main/java/de/assecutor/votianlt/service/SystemInvoiceService.java index 16d7b9c..595667a 100644 --- a/src/main/java/de/assecutor/votianlt/service/SystemInvoiceService.java +++ b/src/main/java/de/assecutor/votianlt/service/SystemInvoiceService.java @@ -10,6 +10,8 @@ import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.font.Standard14Fonts; import org.springframework.stereotype.Service; +import com.itextpdf.html2pdf.HtmlConverter; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; @@ -72,7 +74,7 @@ public class SystemInvoiceService { contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), TITLE_FONT_SIZE); contentStream.setNonStrokingColor(27/255f, 18/255f, 185/255f); // Blue color (RGB values normalized to 0-1) contentStream.newLineAtOffset(MARGIN, yPosition); - contentStream.showText(data.getCompanyName()); + contentStream.showText(data.getCompanyName() != null ? data.getCompanyName() : ""); contentStream.endText(); yPosition -= 30; @@ -82,7 +84,7 @@ public class SystemInvoiceService { contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), FONT_SIZE); contentStream.setNonStrokingColor(27/255f, 18/255f, 185/255f); contentStream.newLineAtOffset(MARGIN, yPosition); - contentStream.showText(data.getCompanySubtitle()); + contentStream.showText(data.getCompanySubtitle() != null ? data.getCompanySubtitle() : ""); contentStream.endText(); yPosition -= 20; @@ -108,7 +110,7 @@ public class SystemInvoiceService { contentStream.beginText(); contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 8); contentStream.newLineAtOffset(leftColumn, yPosition); - contentStream.showText(data.getSenderLine()); + contentStream.showText(data.getSenderLine() != null ? data.getSenderLine() : ""); contentStream.endText(); yPosition -= 20; @@ -143,7 +145,7 @@ public class SystemInvoiceService { contentStream.beginText(); contentStream.newLineAtOffset(dateColumn, recipientStartY - LINE_HEIGHT); - contentStream.showText(data.getInvoiceDate()); + contentStream.showText(data.getInvoiceDate() != null ? data.getInvoiceDate() : ""); contentStream.endText(); // Company address (right side) @@ -158,7 +160,7 @@ public class SystemInvoiceService { contentStream.beginText(); contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), SUBTITLE_FONT_SIZE); contentStream.newLineAtOffset(MARGIN, yPosition); - contentStream.showText("Rechnung " + data.getInvoiceNumber()); + contentStream.showText("Rechnung " + (data.getInvoiceNumber() != null ? data.getInvoiceNumber() : "")); contentStream.endText(); yPosition -= 30; @@ -307,7 +309,7 @@ public class SystemInvoiceService { // VAT contentStream.beginText(); contentStream.newLineAtOffset(rightColumn, yPosition); - contentStream.showText("+ " + data.getVatRate() + "% MwSt.:"); + contentStream.showText("+ " + (data.getVatRate() != null ? data.getVatRate() : "") + "% MwSt.:"); contentStream.endText(); contentStream.beginText(); @@ -431,4 +433,67 @@ public class SystemInvoiceService { return data; } -} \ No newline at end of file + + public byte[] generateInvoicePdfFromHtml() throws Exception { + // Read the HTML template + String htmlContent = readHtmlTemplate(); + + // For simplicity, we'll use the existing sample data to fill the PDF + SystemInvoiceData sampleData = createSampleInvoiceData(); + + // Replace placeholders in HTML with actual data + String filledHtml = fillHtmlWithInvoiceData(htmlContent, sampleData); + + // Create PDF from HTML using iText + return generatePdfFromHtmlString(filledHtml); + } + + private String readHtmlTemplate() throws Exception { + // Read the HTML template file + java.nio.file.Path path = java.nio.file.Paths.get("src/main/resources/templates/vltInvoice.html"); + return java.nio.file.Files.readString(path); + } + + private String fillHtmlWithInvoiceData(String html, SystemInvoiceData data) { + // Replace placeholders in HTML with actual invoice data + String filledHtml = html; + + filledHtml = filledHtml.replace("HHA-2021-07", data.getInvoiceNumber() != null ? data.getInvoiceNumber() : ""); + filledHtml = filledHtml.replace("19.07.2021", data.getInvoiceDate() != null ? data.getInvoiceDate() : ""); + filledHtml = filledHtml.replace("Gemäß unserem Nutzungsvertrag zu der Bestellnummer 45519389 berechnen wir Ihnen für den Monat Juli 2021 wie folgt:", + data.getInvoiceText() != null ? data.getInvoiceText() : ""); + + // Replace recipient address + filledHtml = filledHtml.replace("Hamburger Hochbahn AG
\n Kreditorenbuchhaltung
\n Steinstraße 20
\n 20095 Hamburg", + data.getRecipientName() != null ? data.getRecipientName() : "" + "
\n " + + (data.getRecipientDepartment() != null ? data.getRecipientDepartment() : "") + "
\n " + + (data.getRecipientStreet() != null ? data.getRecipientStreet() : "") + "
\n " + + (data.getRecipientCity() != null ? data.getRecipientCity() : "")); + + // Replace invoice items + if (data.getInvoiceItems() != null && !data.getInvoiceItems().isEmpty()) { + SystemInvoiceItem item = data.getInvoiceItems().get(0); + filledHtml = filledHtml.replace("1", item.getQuantity() != null ? item.getQuantity() : ""); + filledHtml = filledHtml.replace("Mtl. Lizenzgebühr »ILLT«", item.getDescription() != null ? item.getDescription() : ""); + filledHtml = filledHtml.replace("5.639,00 €", item.getUnitPrice() != null ? item.getUnitPrice() : ""); + filledHtml = filledHtml.replace("5.639,00 €", item.getTotalPrice() != null ? item.getTotalPrice() : ""); + } + + // Replace amounts + filledHtml = filledHtml.replace("5.639,00 €", data.getNetAmount() != null ? data.getNetAmount() : ""); + filledHtml = filledHtml.replace("1.071,41 €", data.getVatAmount() != null ? data.getVatAmount() : ""); + filledHtml = filledHtml.replace("6.710,41 €", data.getTotalAmount() != null ? data.getTotalAmount() : ""); + + return filledHtml; + } + + private byte[] generatePdfFromHtmlString(String htmlContent) throws Exception { + // Create PDF using iText library + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // Convert HTML to PDF using iText 8 HtmlConverter + HtmlConverter.convertToPdf(htmlContent, baos); + + return baos.toByteArray(); + } + +} diff --git a/src/main/resources/templates/vltInvoice.html b/src/main/resources/templates/vltInvoice.html new file mode 100644 index 0000000..9c91e78 --- /dev/null +++ b/src/main/resources/templates/vltInvoice.html @@ -0,0 +1,97 @@ + + + + + Rechnung VOTIAN-LT + + + + +
+

Assecutor

+

Data Service GmbH1111

+ +

Empfänger:
+ Hamburger Hochbahasdfasdasn AG
+ Kreditorenbuchhaltung
+ Steinstraße 20
+ 20095 Hamburg +

+ +

Absender:
+ Assecutor Data Service GmbH
+ Gerhart-Hauptmann-Weg 14, 21502 Geesthacht
+ Tel.: 040-181237710 · www.assecutor.de +

+ +

Datum: 19.07.2021

+ +

Rechnung HHA-2021-07

+

Gemäß unserem Nutzungsvertrag zu der Bestellnummer 45519389 + berechnen wir Ihnen für den Monat Juli 2021 wie folgt:

+ + + + + + + + + + + + + + + + + + + + +
MengeBezeichnungEinzelpreisGesamt
1 + Mtl. Lizenzgebühr »ILLT« + 5.639,00 €5.639,00 €
Nettobetrag5.639,00 €
+ 19% MwSt.1.071,41 €
Endbetrag6.710,41 €
+
+ + + + +