Erweiterungen

This commit is contained in:
2025-09-20 10:00:11 +02:00
parent 17b7cc132c
commit 2559982cf5
8 changed files with 581 additions and 4 deletions

View File

@@ -0,0 +1,60 @@
package de.assecutor.votianlt.model.invoices;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "customerInvoices")
public class CustomerInvoice {
@Id
private String id;
private String invoiceNumber;
private String date;
private String text;
// Add other fields as needed
// Constructors
public CustomerInvoice() {
}
public CustomerInvoice(String invoiceNumber, String date, String text) {
this.invoiceNumber = invoiceNumber;
this.date = date;
this.text = text;
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getInvoiceNumber() {
return invoiceNumber;
}
public void setInvoiceNumber(String invoiceNumber) {
this.invoiceNumber = invoiceNumber;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}

View File

@@ -0,0 +1,157 @@
package de.assecutor.votianlt.model.invoices;
import java.util.List;
public class CustomerInvoiceData {
private String invoiceNumber;
private String date;
private String text;
private String recipientName;
private String recipientDepartment;
private String recipientStreet;
private String recipientCity;
private String senderName;
private String senderAddress;
private String senderPhone;
private String senderWebsite;
private List<CustomerInvoiceItem> items;
private String netAmount;
private String vatAmount;
private String totalAmount;
// Constructors
public CustomerInvoiceData() {
}
public CustomerInvoiceData(String invoiceNumber, String date, String text) {
this.invoiceNumber = invoiceNumber;
this.date = date;
this.text = text;
}
// Getters and Setters
public String getInvoiceNumber() {
return invoiceNumber;
}
public void setInvoiceNumber(String invoiceNumber) {
this.invoiceNumber = invoiceNumber;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getRecipientName() {
return recipientName;
}
public void setRecipientName(String recipientName) {
this.recipientName = recipientName;
}
public String getRecipientDepartment() {
return recipientDepartment;
}
public void setRecipientDepartment(String recipientDepartment) {
this.recipientDepartment = recipientDepartment;
}
public String getRecipientStreet() {
return recipientStreet;
}
public void setRecipientStreet(String recipientStreet) {
this.recipientStreet = recipientStreet;
}
public String getRecipientCity() {
return recipientCity;
}
public void setRecipientCity(String recipientCity) {
this.recipientCity = recipientCity;
}
public String getSenderName() {
return senderName;
}
public void setSenderName(String senderName) {
this.senderName = senderName;
}
public String getSenderAddress() {
return senderAddress;
}
public void setSenderAddress(String senderAddress) {
this.senderAddress = senderAddress;
}
public String getSenderPhone() {
return senderPhone;
}
public void setSenderPhone(String senderPhone) {
this.senderPhone = senderPhone;
}
public String getSenderWebsite() {
return senderWebsite;
}
public void setSenderWebsite(String senderWebsite) {
this.senderWebsite = senderWebsite;
}
public List<CustomerInvoiceItem> getItems() {
return items;
}
public void setItems(List<CustomerInvoiceItem> items) {
this.items = items;
}
public String getNetAmount() {
return netAmount;
}
public void setNetAmount(String netAmount) {
this.netAmount = netAmount;
}
public String getVatAmount() {
return vatAmount;
}
public void setVatAmount(String vatAmount) {
this.vatAmount = vatAmount;
}
public String getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(String totalAmount) {
this.totalAmount = totalAmount;
}
}

View File

@@ -0,0 +1,53 @@
package de.assecutor.votianlt.model.invoices;
public class CustomerInvoiceItem {
private String quantity;
private String description;
private String price;
private String total;
// Constructors
public CustomerInvoiceItem() {
}
public CustomerInvoiceItem(String quantity, String description, String unitPrice, String total) {
this.quantity = quantity;
this.description = description;
this.price = unitPrice;
this.total = total;
}
// Getters and Setters
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getTotal() {
return total;
}
public void setTotal(String total) {
this.total = total;
}
}

View File

@@ -10,6 +10,7 @@ import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.StreamResource; import com.vaadin.flow.server.StreamResource;
import de.assecutor.votianlt.pages.base.ui.view.AdminLayout; import de.assecutor.votianlt.pages.base.ui.view.AdminLayout;
import de.assecutor.votianlt.service.CustomerInvoiceService;
import de.assecutor.votianlt.service.SystemInvoiceService; import de.assecutor.votianlt.service.SystemInvoiceService;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
@@ -20,9 +21,11 @@ import java.io.ByteArrayInputStream;
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public class PdfTestView extends VerticalLayout { public class PdfTestView extends VerticalLayout {
private final SystemInvoiceService systemInvoiceService; private final SystemInvoiceService systemInvoiceService;
private final CustomerInvoiceService customerInvoiceService;
public PdfTestView(SystemInvoiceService systemInvoiceService) { public PdfTestView(SystemInvoiceService systemInvoiceService, CustomerInvoiceService customerInvoiceService) {
this.systemInvoiceService = systemInvoiceService; this.systemInvoiceService = systemInvoiceService;
this.customerInvoiceService = customerInvoiceService;
setSpacing(false); setSpacing(false);
setPadding(false); setPadding(false);
@@ -32,12 +35,15 @@ public class PdfTestView extends VerticalLayout {
H2 title = new H2("PDF Test"); H2 title = new H2("PDF Test");
add(title); add(title);
Button generateHtmlPdfButton = new Button("PDF aus vltInvoice.html generieren"); Button generateHtmlPdfButton = new Button("PDF aus system_invoice.html generieren");
generateHtmlPdfButton.addClickListener(e -> generateHtmlPdf()); generateHtmlPdfButton.addClickListener(e -> generateHtmlPdf());
Button generateCustomerInvoicePdfButton = new Button("PDF aus customer_invoice.html generieren");
generateCustomerInvoicePdfButton.addClickListener(e -> generateCustomerInvoicePdf());
// Create button layout // Create button layout
HorizontalLayout buttonLayout = new HorizontalLayout(); HorizontalLayout buttonLayout = new HorizontalLayout();
buttonLayout.add(generateHtmlPdfButton); buttonLayout.add(generateHtmlPdfButton, generateCustomerInvoicePdfButton);
buttonLayout.setSpacing(true); buttonLayout.setSpacing(true);
// Initialize PDF viewer // Initialize PDF viewer
@@ -70,4 +76,24 @@ public class PdfTestView extends VerticalLayout {
5000, Notification.Position.BOTTOM_CENTER); 5000, Notification.Position.BOTTOM_CENTER);
} }
} }
private void generateCustomerInvoicePdf() {
try {
byte[] pdfBytes = customerInvoiceService.generateCustomerInvoicePdf();
StreamResource resource = new StreamResource("customer-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("Customer PDF erfolgreich generiert!", 3000, Notification.Position.BOTTOM_CENTER);
} catch (Exception ex) {
Notification.show("Fehler beim Generieren des Customer PDFs: " + ex.getMessage(),
5000, Notification.Position.BOTTOM_CENTER);
}
}
} }

View File

@@ -0,0 +1,137 @@
package de.assecutor.votianlt.service;
import de.assecutor.votianlt.model.invoices.CustomerInvoice;
import de.assecutor.votianlt.model.invoices.CustomerInvoiceData;
import de.assecutor.votianlt.model.invoices.CustomerInvoiceItem;
import org.springframework.stereotype.Service;
import com.itextpdf.html2pdf.HtmlConverter;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
@Service
public class CustomerInvoiceService {
public CustomerInvoice createCustomerInvoice(String customerId, String jobId) {
// This is a placeholder implementation
// In a real application, this would fetch customer and job data and create an invoice
CustomerInvoice invoice = new CustomerInvoice();
//invoice.setCustomerId(customerId);
//invoice.setJobId(jobId);
return invoice;
}
public CustomerInvoiceData createCustomerInvoiceData(String customerId, String jobId) {
// This is a placeholder implementation
// In a real application, this would fetch customer and job data and create invoice data
CustomerInvoiceData invoiceData = new CustomerInvoiceData();
invoiceData.setInvoiceNumber("INV-" + System.currentTimeMillis());
invoiceData.setDate("2025-09-20");
invoiceData.setText("Rechnung für Auftrag " + jobId);
// Set recipient details
invoiceData.setRecipientName("Kunde Name");
invoiceData.setRecipientDepartment("Abt. XYZ");
invoiceData.setRecipientStreet("Musterstraße 123");
invoiceData.setRecipientCity("12345 Musterstadt");
// Set sender details
invoiceData.setSenderName("Assecutor GmbH");
invoiceData.setSenderAddress("Hauptstraße 456");
invoiceData.setSenderPhone("+49 123 4567890");
invoiceData.setSenderWebsite("https://www.assecutor.de");
// Create sample items
List<CustomerInvoiceItem> items = new ArrayList<>();
CustomerInvoiceItem item1 = new CustomerInvoiceItem("1", "Dienstleistung XYZ", "100,00 €", "100,00 €");
CustomerInvoiceItem item2 = new CustomerInvoiceItem("2", "Material ABC", "50,00 €", "100,00 €");
items.add(item1);
items.add(item2);
invoiceData.setItems(items);
// Set amounts
invoiceData.setNetAmount("200,00 €");
invoiceData.setVatAmount("36,00 €");
invoiceData.setTotalAmount("236,00 €");
return invoiceData;
}
public byte[] generateCustomerInvoicePdf() throws Exception {
// Read the HTML template
String htmlContent = readCustomerInvoiceHtmlTemplate();
// Fill HTML with sample data
CustomerInvoiceData sampleData = createCustomerInvoiceData("customerId", "jobId");
String filledHtml = fillCustomerInvoiceHtmlWithInvoiceData(htmlContent, sampleData);
// Generate PDF from HTML
return generatePdfFromHtmlString(filledHtml);
}
private String readCustomerInvoiceHtmlTemplate() throws Exception {
// Read the HTML template file
java.nio.file.Path path = java.nio.file.Paths.get("src/main/resources/templates/customer_invoice.html");
return java.nio.file.Files.readString(path);
}
private String fillCustomerInvoiceHtmlWithInvoiceData(String html, CustomerInvoiceData data) {
// Replace placeholders in HTML with actual invoice data
String filledHtml = html;
// Replace invoice data placeholders
filledHtml = filledHtml.replace("${invoiceData.invoiceNumber}", data.getInvoiceNumber() != null ? data.getInvoiceNumber() : "");
filledHtml = filledHtml.replace("${invoiceData.date}", data.getDate() != null ? data.getDate() : "");
filledHtml = filledHtml.replace("${invoiceData.text}", data.getText() != null ? data.getText() : "");
// Replace recipient address
filledHtml = filledHtml.replace("${invoiceData.recipientName}", data.getRecipientName() != null ? data.getRecipientName() : "");
filledHtml = filledHtml.replace("${invoiceData.recipientDepartment}", data.getRecipientDepartment() != null ? data.getRecipientDepartment() : "");
filledHtml = filledHtml.replace("${invoiceData.recipientStreet}", data.getRecipientStreet() != null ? data.getRecipientStreet() : "");
filledHtml = filledHtml.replace("${invoiceData.recipientCity}", data.getRecipientCity() != null ? data.getRecipientCity() : "");
// Replace sender details
filledHtml = filledHtml.replace("${invoiceData.senderName}", data.getSenderName() != null ? data.getSenderName() : "");
filledHtml = filledHtml.replace("${invoiceData.senderAddress}", data.getSenderAddress() != null ? data.getSenderAddress() : "");
filledHtml = filledHtml.replace("${invoiceData.senderPhone}", data.getSenderPhone() != null ? data.getSenderPhone() : "");
filledHtml = filledHtml.replace("${invoiceData.senderWebsite}", data.getSenderWebsite() != null ? data.getSenderWebsite() : "");
// Replace invoice items
if (data.getItems() != null && !data.getItems().isEmpty()) {
StringBuilder itemRows = new StringBuilder();
for (CustomerInvoiceItem item : data.getItems()) {
itemRows.append("<tr>");
itemRows.append("<td>").append(item.getQuantity()).append("</td>");
itemRows.append("<td>").append(item.getDescription()).append("</td>");
itemRows.append("<td>").append(item.getPrice()).append("</td>");
itemRows.append("<td>").append(item.getTotal()).append("</td>");
itemRows.append("</tr>");
}
filledHtml = filledHtml.replace("<!-- ITEM_ROWS -->", itemRows.toString());
}
// Replace amounts
filledHtml = filledHtml.replace("${invoiceData.netAmount}", data.getNetAmount() != null ? data.getNetAmount() : "");
filledHtml = filledHtml.replace("${invoiceData.vatAmount}", data.getVatAmount() != null ? data.getVatAmount() : "");
filledHtml = filledHtml.replace("${invoiceData.totalAmount}", 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();
}
}

View File

@@ -51,7 +51,7 @@ public class SystemInvoiceService {
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/system_invoice.html");
return java.nio.file.Files.readString(path); return java.nio.file.Files.readString(path);
} }

View File

@@ -0,0 +1,144 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Rechnung</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.invoice-container {
background-color: white;
padding: 30px;
max-width: 800px;
margin: 0 auto;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.header {
display: flex;
justify-content: space-between;
border-bottom: 2px solid #333;
padding-bottom: 15px;
margin-bottom: 20px;
}
.company-info {
font-size: 14px;
}
.invoice-details {
text-align: right;
font-size: 14px;
}
.invoice-title {
text-align: center;
margin-bottom: 30px;
color: #333;
}
.recipient-info {
margin-bottom: 30px;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
.items-table th, .items-table td {
border: 1px solid #333;
padding: 10px;
text-align: left;
}
.items-table th {
background-color: #f2f2f2;
}
.totals {
width: 100%;
text-align: right;
margin-bottom: 30px;
}
.totals td {
padding: 5px;
}
.signature-section {
margin-top: 50px;
}
.signature-line {
border-top: 1px solid #333;
text-align: center;
padding-top: 5px;
}
</style>
</head>
<body>
<div class="invoice-container">
<div class="header">
<div class="company-info">
<h2>Assecutor GmbH</h2>
<p>Hauptstraße 456</p>
<p>12345 Musterstadt</p>
<p>Telefon: +49 123 4567890</p>
<p>Web: https://www.assecutor.de</p>
</div>
<div class="invoice-details">
<h3>Rechnung</h3>
<p>Rechnungsnummer: <span th:text="${invoiceData.invoiceNumber}">INV-123456789</span></p>
<p>Datum: <span th:text="${invoiceData.date}">2025-09-20</span></p>
</div>
</div>
<h2 class="invoice-title">Rechnung</h2>
<div class="recipient-info">
<h3>Empfänger:</h3>
<p><span th:text="${invoiceData.recipientName}">Kunde Name</span></p>
<p><span th:text="${invoiceData.recipientDepartment}">Abt. XYZ</span></p>
<p><span th:text="${invoiceData.recipientStreet}">Musterstraße 123</span></p>
<p><span th:text="${invoiceData.recipientCity}">12345 Musterstadt</span></p>
</div>
<table class="items-table">
<thead>
<tr>
<th>Menge</th>
<th>Beschreibung</th>
<th>Einzelpreis</th>
<th>Gesamt</th>
</tr>
</thead>
<tbody>
<tr th:each="item : ${invoiceData.items}">
<td th:text="${item.quantity}">1</td>
<td th:text="${item.description}">Dienstleistung XYZ</td>
<td th:text="${item.unitPrice}">100,00 €</td>
<td th:text="${item.total}">100,00 €</td>
</tr>
</tbody>
</table>
<div class="totals">
<table>
<tr>
<td>Netto:</td>
<td th:text="${invoiceData.netAmount}">200,00 €</td>
</tr>
<tr>
<td>USt (19%):</td>
<td th:text="${invoiceData.vatAmount}">36,00 €</td>
</tr>
<tr>
<td><strong>Gesamt:</strong></td>
<td><strong th:text="${invoiceData.totalAmount}">236,00 €</strong></td>
</tr>
</table>
</div>
<div class="signature-section">
<p>Für Assecutor GmbH</p>
<div class="signature-line">
<p>Unterschrift</p>
</div>
</div>
</div>
</body>
</html>