Erweiterungen
This commit is contained in:
7
pom.xml
7
pom.xml
@@ -116,12 +116,7 @@
|
|||||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Apache PDFBox for PDF generation -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.pdfbox</groupId>
|
|
||||||
<artifactId>pdfbox</artifactId>
|
|
||||||
<version>3.0.3</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- iText8 for PDF generation -->
|
<!-- iText8 for PDF generation -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -2,418 +2,38 @@ package de.assecutor.votianlt.service;
|
|||||||
|
|
||||||
import de.assecutor.votianlt.model.invoices.SystemInvoiceData;
|
import de.assecutor.votianlt.model.invoices.SystemInvoiceData;
|
||||||
import de.assecutor.votianlt.model.invoices.SystemInvoiceItem;
|
import de.assecutor.votianlt.model.invoices.SystemInvoiceItem;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDPage;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|
||||||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
|
||||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
|
||||||
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.itextpdf.html2pdf.HtmlConverter;
|
import com.itextpdf.html2pdf.HtmlConverter;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class SystemInvoiceService {
|
public class SystemInvoiceService {
|
||||||
|
|
||||||
private static final float MARGIN = 50;
|
public byte[] generateInvoicePdf(SystemInvoiceData systemInvoiceData) throws Exception {
|
||||||
private static final float FONT_SIZE = 12;
|
// Generate PDF using HTML to PDF conversion
|
||||||
private static final float TITLE_FONT_SIZE = 24;
|
return generateInvoicePdfFromHtml();
|
||||||
private static final float SUBTITLE_FONT_SIZE = 16;
|
|
||||||
private static final float LINE_HEIGHT = 15;
|
|
||||||
|
|
||||||
public byte[] generateInvoicePdf(SystemInvoiceData systemInvoiceData) throws IOException {
|
|
||||||
try (PDDocument document = new PDDocument();
|
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
|
||||||
|
|
||||||
PDPage page = new PDPage(PDRectangle.A4);
|
|
||||||
document.addPage(page);
|
|
||||||
|
|
||||||
try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
|
|
||||||
float yPosition = page.getMediaBox().getHeight() - MARGIN;
|
|
||||||
|
|
||||||
// Draw header
|
|
||||||
yPosition = drawHeader(contentStream, yPosition, systemInvoiceData);
|
|
||||||
yPosition -= 30;
|
|
||||||
|
|
||||||
// Draw company and recipient info
|
|
||||||
yPosition = drawAddresses(contentStream, yPosition, systemInvoiceData);
|
|
||||||
yPosition -= 30;
|
|
||||||
|
|
||||||
// Draw invoice details
|
|
||||||
yPosition = drawInvoiceDetails(contentStream, yPosition, systemInvoiceData);
|
|
||||||
yPosition -= 30;
|
|
||||||
|
|
||||||
// Draw items table
|
|
||||||
yPosition = drawItemsTable(contentStream, yPosition, systemInvoiceData);
|
|
||||||
yPosition -= 30;
|
|
||||||
|
|
||||||
// Draw totals
|
|
||||||
yPosition = drawTotals(contentStream, yPosition, systemInvoiceData);
|
|
||||||
yPosition -= 30;
|
|
||||||
|
|
||||||
// Draw payment terms
|
|
||||||
yPosition = drawPaymentTerms(contentStream, yPosition, systemInvoiceData);
|
|
||||||
|
|
||||||
// Draw footer at bottom of page
|
|
||||||
drawFooter(contentStream, page, systemInvoiceData);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.save(outputStream);
|
|
||||||
return outputStream.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private float drawHeader(PDPageContentStream contentStream, float yPosition, SystemInvoiceData data) throws IOException {
|
public byte[] generateInvoicePdfFromHtml() throws Exception {
|
||||||
// Company name
|
// Read the HTML template
|
||||||
contentStream.beginText();
|
String htmlContent = readHtmlTemplate();
|
||||||
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() != null ? data.getCompanyName() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
yPosition -= 30;
|
// Fill HTML with sample data
|
||||||
|
SystemInvoiceData sampleData = createSampleInvoiceData();
|
||||||
|
String filledHtml = fillHtmlWithInvoiceData(htmlContent, sampleData);
|
||||||
|
|
||||||
// Company subtitle
|
// Generate PDF from HTML
|
||||||
contentStream.beginText();
|
return generatePdfFromHtmlString(filledHtml);
|
||||||
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() != null ? data.getCompanySubtitle() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
yPosition -= 20;
|
|
||||||
|
|
||||||
// Draw line
|
|
||||||
contentStream.setStrokingColor(27/255f, 18/255f, 185/255f);
|
|
||||||
contentStream.setLineWidth(2);
|
|
||||||
contentStream.moveTo(MARGIN, yPosition);
|
|
||||||
contentStream.lineTo(PDRectangle.A4.getWidth() - MARGIN, yPosition);
|
|
||||||
contentStream.stroke();
|
|
||||||
|
|
||||||
return yPosition - 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float drawAddresses(PDPageContentStream contentStream, float yPosition, SystemInvoiceData data) throws IOException {
|
|
||||||
contentStream.setNonStrokingColor(0f, 0f, 0f); // Black
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), FONT_SIZE);
|
|
||||||
|
|
||||||
float leftColumn = MARGIN;
|
|
||||||
float rightColumn = 350;
|
|
||||||
|
|
||||||
// Sender line
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 8);
|
|
||||||
contentStream.newLineAtOffset(leftColumn, yPosition);
|
|
||||||
contentStream.showText(data.getSenderLine() != null ? data.getSenderLine() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
yPosition -= 20;
|
|
||||||
float recipientStartY = yPosition; // Store starting position for date alignment
|
|
||||||
|
|
||||||
// Recipient address
|
|
||||||
String[] recipientLines = {
|
|
||||||
data.getRecipientName(),
|
|
||||||
data.getRecipientDepartment(),
|
|
||||||
data.getRecipientStreet(),
|
|
||||||
data.getRecipientCity()
|
|
||||||
};
|
|
||||||
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), FONT_SIZE);
|
|
||||||
for (String line : recipientLines) {
|
|
||||||
if (line != null && !line.trim().isEmpty()) {
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(leftColumn, yPosition);
|
|
||||||
contentStream.showText(line);
|
|
||||||
contentStream.endText();
|
|
||||||
yPosition -= LINE_HEIGHT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Date (right aligned, same vertical level as recipient)
|
|
||||||
float dateColumn = 450; // Move further to the right
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), FONT_SIZE);
|
|
||||||
contentStream.newLineAtOffset(dateColumn, recipientStartY);
|
|
||||||
contentStream.showText("Datum");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(dateColumn, recipientStartY - LINE_HEIGHT);
|
|
||||||
contentStream.showText(data.getInvoiceDate() != null ? data.getInvoiceDate() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
// Company address (right side)
|
|
||||||
float rightYPosition = yPosition + (recipientLines.length * LINE_HEIGHT);
|
|
||||||
|
|
||||||
return Math.min(yPosition, rightYPosition) - 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float drawInvoiceDetails(PDPageContentStream contentStream, float yPosition, SystemInvoiceData data) throws IOException {
|
|
||||||
|
|
||||||
// Invoice title
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), SUBTITLE_FONT_SIZE);
|
|
||||||
contentStream.newLineAtOffset(MARGIN, yPosition);
|
|
||||||
contentStream.showText("Rechnung " + (data.getInvoiceNumber() != null ? data.getInvoiceNumber() : ""));
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
yPosition -= 30;
|
|
||||||
|
|
||||||
// Invoice text
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), FONT_SIZE);
|
|
||||||
contentStream.newLineAtOffset(MARGIN, yPosition);
|
|
||||||
|
|
||||||
// Split long text into multiple lines
|
|
||||||
String invoiceText = data.getInvoiceText();
|
|
||||||
if (invoiceText != null && invoiceText.length() > 80) {
|
|
||||||
String[] words = invoiceText.split(" ");
|
|
||||||
StringBuilder currentLine = new StringBuilder();
|
|
||||||
for (String word : words) {
|
|
||||||
if (currentLine.length() + word.length() + 1 > 80) {
|
|
||||||
contentStream.showText(currentLine.toString());
|
|
||||||
contentStream.newLineAtOffset(0, -LINE_HEIGHT);
|
|
||||||
currentLine = new StringBuilder(word);
|
|
||||||
} else {
|
|
||||||
if (currentLine.length() > 0) currentLine.append(" ");
|
|
||||||
currentLine.append(word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentLine.length() > 0) {
|
|
||||||
contentStream.showText(currentLine.toString());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
contentStream.showText(invoiceText != null ? invoiceText : "");
|
|
||||||
}
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
return yPosition - 40;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float drawItemsTable(PDPageContentStream contentStream, float yPosition, SystemInvoiceData data) throws IOException {
|
|
||||||
float[] columnWidths = {60, 300, 100, 100}; // Menge, Bezeichnung, Einzelpreis, Gesamt
|
|
||||||
float rowHeight = 20;
|
|
||||||
|
|
||||||
// Calculate actual table width based on column widths
|
|
||||||
float actualTableWidth = 0;
|
|
||||||
for (float width : columnWidths) {
|
|
||||||
actualTableWidth += width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add 2cm margin to the right of the gray header
|
|
||||||
float rightMargin = 2 * 28.35f; // 2cm in points (1cm = 28.35pt)
|
|
||||||
float headerWidth = actualTableWidth + rightMargin;
|
|
||||||
|
|
||||||
// Table header
|
|
||||||
contentStream.setNonStrokingColor(230/255f, 230/255f, 230/255f); // Light gray background
|
|
||||||
contentStream.addRect(MARGIN, yPosition - rowHeight, headerWidth, rowHeight);
|
|
||||||
contentStream.fill();
|
|
||||||
|
|
||||||
contentStream.setNonStrokingColor(0f, 0f, 0f); // Black
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), 10);
|
|
||||||
|
|
||||||
String[] headers = {"Menge", "Bezeichnung", "Einzelpreis", "Gesamt"};
|
|
||||||
float xOffset = MARGIN + 5;
|
|
||||||
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(xOffset, yPosition - 15);
|
|
||||||
contentStream.showText(headers[0]);
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
xOffset += columnWidths[0];
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(xOffset, yPosition - 15);
|
|
||||||
contentStream.showText(headers[1]);
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
xOffset += columnWidths[1];
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(xOffset, yPosition - 15);
|
|
||||||
contentStream.showText(headers[2]);
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
xOffset += columnWidths[2];
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(xOffset, yPosition - 15);
|
|
||||||
contentStream.showText(headers[3]);
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
yPosition -= rowHeight;
|
|
||||||
|
|
||||||
// Table rows
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 10);
|
|
||||||
|
|
||||||
if (data.getInvoiceItems() != null) {
|
|
||||||
for (SystemInvoiceItem item : data.getInvoiceItems()) {
|
|
||||||
xOffset = MARGIN + 5;
|
|
||||||
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(xOffset, yPosition - 15);
|
|
||||||
contentStream.showText(item.getQuantity() != null ? item.getQuantity() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
xOffset += columnWidths[0];
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(xOffset, yPosition - 15);
|
|
||||||
contentStream.showText(item.getDescription() != null ? item.getDescription() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
xOffset += columnWidths[1];
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(xOffset, yPosition - 15);
|
|
||||||
contentStream.showText(item.getUnitPrice() != null ? item.getUnitPrice() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
xOffset += columnWidths[2];
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(xOffset, yPosition - 15);
|
|
||||||
contentStream.showText(item.getTotalPrice() != null ? item.getTotalPrice() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
yPosition -= rowHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add some empty rows for spacing
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
yPosition -= rowHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
return yPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float drawTotals(PDPageContentStream contentStream, float yPosition, SystemInvoiceData data) throws IOException {
|
|
||||||
float rightColumn = 400;
|
|
||||||
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), FONT_SIZE);
|
|
||||||
|
|
||||||
// Net amount
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(rightColumn, yPosition);
|
|
||||||
contentStream.showText("Nettobetrag:");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(rightColumn + 100, yPosition);
|
|
||||||
contentStream.showText(data.getNetAmount() != null ? data.getNetAmount() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
yPosition -= LINE_HEIGHT;
|
|
||||||
|
|
||||||
// VAT
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(rightColumn, yPosition);
|
|
||||||
contentStream.showText("+ " + (data.getVatRate() != null ? data.getVatRate() : "") + "% MwSt.:");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(rightColumn + 100, yPosition);
|
|
||||||
contentStream.showText(data.getVatAmount() != null ? data.getVatAmount() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
yPosition -= LINE_HEIGHT;
|
|
||||||
|
|
||||||
// Total amount
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), FONT_SIZE);
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(rightColumn, yPosition);
|
|
||||||
contentStream.showText("Endbetrag:");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(rightColumn + 100, yPosition);
|
|
||||||
contentStream.showText(data.getTotalAmount() != null ? data.getTotalAmount() : "");
|
|
||||||
contentStream.endText();
|
|
||||||
|
|
||||||
return yPosition - 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float drawPaymentTerms(PDPageContentStream contentStream, float yPosition, SystemInvoiceData data) throws IOException {
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), FONT_SIZE);
|
|
||||||
|
|
||||||
// Payment terms with text wrapping
|
|
||||||
String paymentTerms = data.getPaymentTerms();
|
|
||||||
if (paymentTerms != null && !paymentTerms.trim().isEmpty()) {
|
|
||||||
float maxWidth = PDRectangle.A4.getWidth() - 2 * MARGIN;
|
|
||||||
yPosition = drawWrappedText(contentStream, paymentTerms, MARGIN, yPosition, maxWidth, FONT_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return yPosition - 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float drawWrappedText(PDPageContentStream contentStream, String text, float x, float y, float maxWidth, float fontSize) throws IOException {
|
|
||||||
String[] words = text.split(" ");
|
|
||||||
StringBuilder currentLine = new StringBuilder();
|
|
||||||
float currentY = y;
|
|
||||||
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(x, currentY);
|
|
||||||
|
|
||||||
for (String word : words) {
|
|
||||||
String testLine = currentLine.length() > 0 ? currentLine + " " + word : word;
|
|
||||||
|
|
||||||
// Estimate text width (rough calculation)
|
|
||||||
float textWidth = estimateTextWidth(testLine, fontSize);
|
|
||||||
|
|
||||||
if (textWidth > maxWidth && currentLine.length() > 0) {
|
|
||||||
// Print current line and start new line
|
|
||||||
contentStream.showText(currentLine.toString());
|
|
||||||
currentLine = new StringBuilder(word);
|
|
||||||
currentY -= LINE_HEIGHT;
|
|
||||||
contentStream.newLineAtOffset(0, -LINE_HEIGHT);
|
|
||||||
} else {
|
|
||||||
currentLine = new StringBuilder(testLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print remaining text
|
|
||||||
if (currentLine.length() > 0) {
|
|
||||||
contentStream.showText(currentLine.toString());
|
|
||||||
currentY -= LINE_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
contentStream.endText();
|
|
||||||
return currentY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float estimateTextWidth(String text, float fontSize) {
|
|
||||||
// Rough estimation: average character width is about 0.6 * font size
|
|
||||||
return text.length() * fontSize * 0.6f;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawFooter(PDPageContentStream contentStream, PDPage page, SystemInvoiceData data) throws IOException {
|
|
||||||
contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 8);
|
|
||||||
|
|
||||||
// Footer text (company details) - positioned at absolute bottom
|
|
||||||
String footerText = data.getFooterText();
|
|
||||||
if (footerText != null) {
|
|
||||||
String[] footerLines = footerText.split("<br>");
|
|
||||||
|
|
||||||
// Calculate footer position from bottom of page
|
|
||||||
float lineSpacing = 10; // 10 points between lines
|
|
||||||
float footerBottomMargin = 30; // 30 points from absolute bottom
|
|
||||||
|
|
||||||
// Start from the bottom and work upwards
|
|
||||||
float currentY = footerBottomMargin + (footerLines.length - 1) * lineSpacing;
|
|
||||||
|
|
||||||
for (String line : footerLines) {
|
|
||||||
contentStream.beginText();
|
|
||||||
contentStream.newLineAtOffset(MARGIN, currentY);
|
|
||||||
contentStream.showText(line.trim());
|
|
||||||
contentStream.endText();
|
|
||||||
currentY -= lineSpacing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SystemInvoiceData createSampleInvoiceData() {
|
public SystemInvoiceData createSampleInvoiceData() {
|
||||||
SystemInvoiceData data = new SystemInvoiceData();
|
SystemInvoiceData data = new SystemInvoiceData();
|
||||||
|
|
||||||
|
// Set sample data
|
||||||
data.setInvoiceNumber("HHA-2021-007");
|
data.setInvoiceNumber("HHA-2021-007");
|
||||||
data.setInvoiceDate("19.07.2021");
|
data.setInvoiceDate("19.07.2021");
|
||||||
data.setInvoiceText("Gemäß unserem Nutzungsvertrag zu der Bestellnummer 45519389 berechnen wir Ihnen für den Monat Juli 2021 wie folgt:");
|
data.setInvoiceText("Gemäß unserem Nutzungsvertrag zu der Bestellnummer 45519389 berechnen wir Ihnen für den Monat Juli 2021 wie folgt:");
|
||||||
@@ -434,66 +54,49 @@ public class SystemInvoiceService {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
private String readHtmlTemplate() throws Exception {
|
||||||
// Read the HTML template file
|
// Read the HTML template file
|
||||||
java.nio.file.Path path = java.nio.file.Paths.get("src/main/resources/templates/vltInvoice.html");
|
java.nio.file.Path path = java.nio.file.Paths.get("src/main/resources/templates/vltInvoice.html");
|
||||||
return java.nio.file.Files.readString(path);
|
return java.nio.file.Files.readString(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String fillHtmlWithInvoiceData(String html, SystemInvoiceData data) {
|
private String fillHtmlWithInvoiceData(String html, SystemInvoiceData data) {
|
||||||
// Replace placeholders in HTML with actual invoice data
|
// Replace placeholders in HTML with actual invoice data
|
||||||
String filledHtml = html;
|
String filledHtml = html;
|
||||||
|
|
||||||
filledHtml = filledHtml.replace("HHA-2021-07", data.getInvoiceNumber() != null ? data.getInvoiceNumber() : "");
|
// Replace invoice data placeholders
|
||||||
|
filledHtml = filledHtml.replace("HHA-2021-007", data.getInvoiceNumber() != null ? data.getInvoiceNumber() : "");
|
||||||
filledHtml = filledHtml.replace("19.07.2021", data.getInvoiceDate() != null ? data.getInvoiceDate() : "");
|
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:",
|
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() : "");
|
data.getInvoiceText() != null ? data.getInvoiceText() : "");
|
||||||
|
|
||||||
// Replace recipient address
|
// Replace recipient address
|
||||||
filledHtml = filledHtml.replace("Hamburger Hochbahn AG<br>\n Kreditorenbuchhaltung<br>\n Steinstraße 20<br>\n 20095 Hamburg",
|
filledHtml = filledHtml.replace("Hamburger Hochbahn AG", data.getRecipientName() != null ? data.getRecipientName() : "");
|
||||||
data.getRecipientName() != null ? data.getRecipientName() : "" + "<br>\n " +
|
filledHtml = filledHtml.replace("Kreditorenbuchhaltung", data.getRecipientDepartment() != null ? data.getRecipientDepartment() : "");
|
||||||
(data.getRecipientDepartment() != null ? data.getRecipientDepartment() : "") + "<br>\n " +
|
filledHtml = filledHtml.replace("Steinstraße 20", data.getRecipientStreet() != null ? data.getRecipientStreet() : "");
|
||||||
(data.getRecipientStreet() != null ? data.getRecipientStreet() : "") + "<br>\n " +
|
filledHtml = filledHtml.replace("20095 Hamburg", data.getRecipientCity() != null ? data.getRecipientCity() : "");
|
||||||
(data.getRecipientCity() != null ? data.getRecipientCity() : ""));
|
|
||||||
|
|
||||||
// Replace invoice items
|
// Replace invoice items
|
||||||
if (data.getInvoiceItems() != null && !data.getInvoiceItems().isEmpty()) {
|
if (data.getInvoiceItems() != null && !data.getInvoiceItems().isEmpty()) {
|
||||||
SystemInvoiceItem item = data.getInvoiceItems().get(0);
|
SystemInvoiceItem item = data.getInvoiceItems().getFirst();
|
||||||
filledHtml = filledHtml.replace("1", item.getQuantity() != null ? item.getQuantity() : "");
|
|
||||||
filledHtml = filledHtml.replace("Mtl. Lizenzgebühr »ILLT«", item.getDescription() != null ? item.getDescription() : "");
|
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
|
// Replace amounts
|
||||||
filledHtml = filledHtml.replace("5.639,00 €", data.getNetAmount() != null ? data.getNetAmount() : "");
|
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("1.071,41 €", data.getVatAmount() != null ? data.getVatAmount() : "");
|
||||||
filledHtml = filledHtml.replace("6.710,41 €", data.getTotalAmount() != null ? data.getTotalAmount() : "");
|
filledHtml = filledHtml.replace("6.710,41 €", data.getTotalAmount() != null ? data.getTotalAmount() : "");
|
||||||
|
|
||||||
return filledHtml;
|
return filledHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] generatePdfFromHtmlString(String htmlContent) throws Exception {
|
private byte[] generatePdfFromHtmlString(String htmlContent) throws Exception {
|
||||||
// Create PDF using iText library
|
// Create PDF using iText library
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
// Convert HTML to PDF using iText 8 HtmlConverter
|
// Convert HTML to PDF using iText 8 HtmlConverter
|
||||||
HtmlConverter.convertToPdf(htmlContent, baos);
|
HtmlConverter.convertToPdf(htmlContent, baos);
|
||||||
|
|
||||||
return baos.toByteArray();
|
return baos.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user