diff --git a/src/main/bundles/dev.bundle b/src/main/bundles/dev.bundle index fbb4a31..f28ff6a 100644 Binary files a/src/main/bundles/dev.bundle and b/src/main/bundles/dev.bundle differ diff --git a/src/main/frontend/invoice-generator/invoice-generator.js b/src/main/frontend/invoice-generator/invoice-generator.js index bb65bd3..246a0b6 100644 --- a/src/main/frontend/invoice-generator/invoice-generator.js +++ b/src/main/frontend/invoice-generator/invoice-generator.js @@ -449,6 +449,15 @@ ctx.lineTo(el.x + (el.width || 200), el.y); ctx.stroke(); break; + + case 'vline': + ctx.strokeStyle = el.color || '#333333'; + ctx.lineWidth = el.strokeWidth || 1; + ctx.beginPath(); + ctx.moveTo(el.x, el.y); + ctx.lineTo(el.x, el.y + (el.height || 200)); + ctx.stroke(); + break; case 'image': if (el.imageData) { @@ -699,6 +708,11 @@ el.width = 200; el.height = 2; break; + case 'vline': + el.text = ''; + el.width = 2; + el.height = 200; + break; case 'image': el.text = 'Bild'; el.width = 100; diff --git a/src/main/frontend/invoice-generator/profile-invoice-generator.js b/src/main/frontend/invoice-generator/profile-invoice-generator.js index d80570f..da92ec6 100644 --- a/src/main/frontend/invoice-generator/profile-invoice-generator.js +++ b/src/main/frontend/invoice-generator/profile-invoice-generator.js @@ -265,7 +265,9 @@ window.initProfileInvoiceGenerator = function() { // Always use black text for static elements, otherwise use element color ctx.fillStyle = el.isStatic ? '#000000' : (el.color || '#333333'); - ctx.font = (el.fontStyle || '') + ' ' + fontSize + 'px Arial'; + // Masterdata elements are never bold; other elements respect their fontStyle + var fontWeight = (el.isStatic && !el.isCustomer) ? '' : (el.fontStyle || ''); + ctx.font = (fontWeight ? fontWeight + ' ' : '') + fontSize + 'px Arial'; ctx.textBaseline = 'top'; lines.forEach(function(line) { @@ -1108,6 +1110,17 @@ window.initProfileInvoiceGenerator = function() { }; }; + window.updateProfileMasterdataValue = function(key, value) { + if (!window.masterdataValues) window.masterdataValues = {}; + window.masterdataValues[key] = value; + elements.forEach(function(el) { + if (el.variable === key) { + el.text = value; + } + }); + draw(); + }; + draw(); window.profileInvoiceState.initialized = true; console.log('Profile canvas initialized with ' + elements.length + ' elements'); diff --git a/src/main/java/de/assecutor/votianlt/pages/view/EditProfileView.java b/src/main/java/de/assecutor/votianlt/pages/view/EditProfileView.java index d52df74..6ae9c57 100644 --- a/src/main/java/de/assecutor/votianlt/pages/view/EditProfileView.java +++ b/src/main/java/de/assecutor/votianlt/pages/view/EditProfileView.java @@ -327,6 +327,20 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle billingEnabled.setValue(true); // Standardmäßig aktiviert billingTab.add(billingEnabled); + prefixField.setLabel(getTranslation("profile.billing.prefix")); + prefixField.setPlaceholder("z.B. RE-2024-"); + prefixField.setMaxWidth("300px"); + prefixField.setVisible(true); + prefixField.addBlurListener(e -> { + saveInvoiceData(); + String p = prefixField.getValue(); + String invNr = (p != null && !p.isBlank() ? p : "") + "12345"; + getElement().executeJs( + "if (window.updateProfileMasterdataValue) { window.updateProfileMasterdataValue('masterdata.invoice_number', '" + + invNr.replace("'", "\\'") + "'); }"); + }); + billingTab.add(prefixField); + // Hauptlayout: Links (Templates) | Mitte (Canvas) | Rechts (Eigenschaften) final HorizontalLayout mainLayout = new HorizontalLayout(); mainLayout.setWidthFull(); @@ -384,13 +398,6 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle actionLayout.setSpacing(true); actionLayout.getStyle().set("margin-top", "var(--lumo-space-s)"); - Button clearButton = new Button(getTranslation("button.clear"), new Icon(VaadinIcon.TRASH)); - clearButton.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY); - clearButton.addClickListener(e -> { - getElement().executeJs("if (window.clearProfileCanvas) { window.clearProfileCanvas(); }"); - Notification.show(getTranslation("profile.canvas.cleared"), 2000, Notification.Position.BOTTOM_CENTER); - }); - Button previewPdfButton = new Button(getTranslation("button.preview"), new Icon(VaadinIcon.EYE)); previewPdfButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_SUCCESS); previewPdfButton.addClickListener(e -> generatePreviewPdfFromProfile()); @@ -424,7 +431,7 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle }); }); - actionLayout.add(clearButton, previewPdfButton, saveTemplateButton); + actionLayout.add(previewPdfButton, saveTemplateButton); billingTab.add(actionLayout); // Initialen Zustand setzen (sichtbar da checkbox standardmäßig true) @@ -435,6 +442,7 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle // Sichtbarkeit des Invoice Generators an Checkbox binden billingEnabled.addValueChangeListener(e -> { boolean visible = e.getValue(); + prefixField.setVisible(visible); mainLayout.setVisible(visible); actionLayout.setVisible(visible); }); @@ -866,7 +874,7 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle templateData = result.toString(); } byte[] pdfBytes = customerInvoiceService.generatePdfFromCanvasTemplate(templateData, - currentUser); + currentUser, prefixField.getValue()); showPdfInDialog(pdfBytes); } catch (Exception ex) { Notification.show(getTranslation("profile.pdf.preview.error", ex.getMessage()), 3000, @@ -958,6 +966,8 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle "masterdata.email", email.isEmpty() ? getTranslation("profile.invoice.placeholder.email") : email); Div senderPhone = createVariableTemplate(getTranslation("profile.invoice.phone"), VaadinIcon.PHONE, "masterdata.phone", phone.isEmpty() ? getTranslation("profile.invoice.placeholder.phone") : phone); + Div invoiceNumber = createVariableTemplate(getTranslation("profile.invoice.element.invoicenumber"), + VaadinIcon.HASH, "masterdata.invoice_number", "RE-2024-0001"); // Bereich 2: Leistungen Span servicesHeader = new Span(getTranslation("profile.services.label")); @@ -1017,7 +1027,7 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle "image"); panel.add(invoiceHeader, senderCompany, senderName, senderAddress, senderCity, senderEmail, senderPhone, - servicesHeader, servicesListBlock, servicesNetBlock, servicesVatBlock, servicesGrossBlock, + invoiceNumber, servicesHeader, servicesListBlock, servicesNetBlock, servicesVatBlock, servicesGrossBlock, customerHeader, customerCompany, customerName, customerAddress, customerCity, customerEmail, customerPhone, freeHeader, textBlock, headerBlock, dateBlock, customerBlock, companyBlock, amountBlock, lineBlock, imageBlock); @@ -1422,11 +1432,14 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle String city = safe(currentUser.getZip()) + " " + safe(currentUser.getCity()); String email = safe(currentUser.getEmail()); String phone = safe(currentUser.getPhone()); + String prefix = prefixField.getValue(); + String invoiceNumber = (prefix != null && !prefix.isBlank() ? prefix : "") + "12345"; String masterdataJson = "{" + "'masterdata.company_name': '" + company.replace("'", "\\'") + "'," + "'masterdata.contact_name': '" + fullName.replace("'", "\\'") + "'," + "'masterdata.street': '" + street.replace("'", "\\'") + "'," + "'masterdata.city': '" + city.replace("'", "\\'") + "'," + "'masterdata.email': '" + email.replace("'", "\\'") - + "'," + "'masterdata.phone': '" + phone.replace("'", "\\'") + "'" + "}"; + + "'," + "'masterdata.phone': '" + phone.replace("'", "\\'") + "'," + + "'masterdata.invoice_number': '" + invoiceNumber.replace("'", "\\'") + "'" + "}"; getElement().executeJs("setTimeout(function() { " + " if (window.loadProfileTemplate && document.getElementById('invoice-canvas-container-profile')) { " + " console.log('Loading template into canvas...'); " + " window.masterdataValues = " diff --git a/src/main/java/de/assecutor/votianlt/pages/view/InvoiceGeneratorView.java b/src/main/java/de/assecutor/votianlt/pages/view/InvoiceGeneratorView.java index dc85d32..0d4ed94 100644 --- a/src/main/java/de/assecutor/votianlt/pages/view/InvoiceGeneratorView.java +++ b/src/main/java/de/assecutor/votianlt/pages/view/InvoiceGeneratorView.java @@ -123,11 +123,13 @@ public class InvoiceGeneratorView extends VerticalLayout implements HasDynamicTi VaadinIcon.COIN_PILES, "amount"); Div lineBlock = createDraggableTemplate(getTranslation("invoicegenerator.template.line"), VaadinIcon.LINE_V, "line"); + Div vlineBlock = createDraggableTemplate(getTranslation("invoicegenerator.template.vline"), + VaadinIcon.LINE_BAR_CHART, "vline"); Div imageBlock = createDraggableTemplate(getTranslation("invoicegenerator.template.image"), VaadinIcon.PICTURE, "image"); panel.add(header, textBlock, headerBlock, dateBlock, customerBlock, companyBlock, amountBlock, lineBlock, - imageBlock); + vlineBlock, imageBlock); return panel; } @@ -409,7 +411,7 @@ public class InvoiceGeneratorView extends VerticalLayout implements HasDynamicTi } // Text Feld (nur für Text-Elemente) - if (!"line".equals(elementType) && !"image".equals(elementType)) { + if (!"line".equals(elementType) && !"vline".equals(elementType) && !"image".equals(elementType)) { TextField textField = new TextField("Text"); textField.setValue(text != null ? text : ""); textField.setWidthFull(); @@ -451,7 +453,7 @@ public class InvoiceGeneratorView extends VerticalLayout implements HasDynamicTi propertiesPanel.add(yField); // Font Size (nur für Text-Elemente) - if (!"line".equals(elementType) && !"image".equals(elementType)) { + if (!"line".equals(elementType) && !"vline".equals(elementType) && !"image".equals(elementType)) { TextField fontSizeField = new TextField(getTranslation("invoicegenerator.fontsize.label")); fontSizeField.setValue(fontSize != null ? String.valueOf(fontSize) : "16"); fontSizeField.setWidthFull(); diff --git a/src/main/java/de/assecutor/votianlt/service/CustomerInvoiceService.java b/src/main/java/de/assecutor/votianlt/service/CustomerInvoiceService.java index 076c219..466153b 100644 --- a/src/main/java/de/assecutor/votianlt/service/CustomerInvoiceService.java +++ b/src/main/java/de/assecutor/votianlt/service/CustomerInvoiceService.java @@ -248,11 +248,17 @@ public class CustomerInvoiceService { * representation of the canvas elements and converts it to PDF. */ public byte[] generatePdfFromCanvasTemplate(String jsonTemplateData) throws Exception { - return generatePdfFromCanvasTemplate(jsonTemplateData, null); + return generatePdfFromCanvasTemplate(jsonTemplateData, null, null); } public byte[] generatePdfFromCanvasTemplate(String jsonTemplateData, de.assecutor.votianlt.model.User user) throws Exception { + return generatePdfFromCanvasTemplate(jsonTemplateData, user, null); + } + + public byte[] generatePdfFromCanvasTemplate(String jsonTemplateData, de.assecutor.votianlt.model.User user, + String invoicePrefix) + throws Exception { // Parse the JSON template data com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(); com.fasterxml.jackson.databind.JsonNode rootNode = mapper.readTree(jsonTemplateData); @@ -287,6 +293,8 @@ public class CustomerInvoiceService { variables.put("masterdata.city", safe(user.getZip()) + " " + safe(user.getCity())); variables.put("masterdata.email", safe(user.getEmail())); variables.put("masterdata.phone", safe(user.getPhone())); + variables.put("masterdata.invoice_number", + (invoicePrefix != null && !invoicePrefix.isBlank() ? invoicePrefix : "") + "12345"); } else { // Default values for preview without user variables.put("masterdata.company_name", "Meine Firma GmbH"); @@ -295,6 +303,8 @@ public class CustomerInvoiceService { variables.put("masterdata.city", "12345 Musterstadt"); variables.put("masterdata.email", "kontakt@firma.de"); variables.put("masterdata.phone", "0123 456789"); + variables.put("masterdata.invoice_number", + (invoicePrefix != null && !invoicePrefix.isBlank() ? invoicePrefix : "") + "12345"); } // Customer data (placeholder for now - would come from job/customer selection) @@ -348,7 +358,6 @@ public class CustomerInvoiceService { } int fontSize = element.has("fontSize") ? element.get("fontSize").asInt(14) : 14; - String fontStyle = element.has("fontStyle") ? element.get("fontStyle").asText("") : ""; String color = element.has("color") ? element.get("color").asText("#333333") : "#333333"; // Convert percentages to mm (A4 is 210mm x 297mm) @@ -361,23 +370,27 @@ public class CustomerInvoiceService { htmlBuilder.append("style='"); htmlBuilder.append("left:").append(String.format(java.util.Locale.US, "%.2f", mmX)).append("mm;"); htmlBuilder.append("top:").append(String.format(java.util.Locale.US, "%.2f", mmY)).append("mm;"); - htmlBuilder.append("width:").append(String.format(java.util.Locale.US, "%.2f", mmWidth)).append("mm;"); - htmlBuilder.append("height:").append(String.format(java.util.Locale.US, "%.2f", mmHeight)) - .append("mm;"); - htmlBuilder.append("font-size:").append(fontSize).append("pt;"); - htmlBuilder.append("line-height:").append(String.format(java.util.Locale.US, "%.2f", fontSize * 1.2)) - .append("pt;"); - htmlBuilder.append("color:").append(color).append(";"); - if (!fontStyle.isEmpty()) { - if (fontStyle.contains("bold")) - htmlBuilder.append("font-weight:bold;"); - } - // For services.list use block display to allow table to fill width - if ("services.list".equals(variable)) { - htmlBuilder.append("display:block;overflow:visible;padding:0;"); + if ("line".equals(type)) { + htmlBuilder.append("width:").append(String.format(java.util.Locale.US, "%.2f", mmWidth)).append("mm;"); + htmlBuilder.append("height:0;border-top:1px solid #333;"); + } else if ("vline".equals(type)) { + htmlBuilder.append("width:0;border-left:1px solid #333;"); + htmlBuilder.append("height:").append(String.format(java.util.Locale.US, "%.2f", mmHeight)).append("mm;"); } else { - // Vertically center content for other elements - htmlBuilder.append("display:flex;align-items:center;"); + htmlBuilder.append("width:").append(String.format(java.util.Locale.US, "%.2f", mmWidth)).append("mm;"); + htmlBuilder.append("height:").append(String.format(java.util.Locale.US, "%.2f", mmHeight)) + .append("mm;"); + htmlBuilder.append("font-size:").append(fontSize).append("pt;"); + htmlBuilder.append("line-height:").append(String.format(java.util.Locale.US, "%.2f", fontSize * 1.2)) + .append("pt;"); + htmlBuilder.append("color:").append(color).append(";"); + // For services.list use block display to allow table to fill width + if ("services.list".equals(variable)) { + htmlBuilder.append("display:block;overflow:visible;padding:0;"); + } else { + // Vertically center content for other elements + htmlBuilder.append("display:flex;align-items:center;"); + } } htmlBuilder.append("'"); htmlBuilder.append(">"); @@ -406,14 +419,13 @@ public class CustomerInvoiceService { if (text != null) { text = text.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """) .replace("'", "'"); + // Convert newlines to
for multi-line elements (e.g. customer address) + text = text.replace("\n", "
"); } else { text = ""; } - if ("line".equals(type)) { - htmlBuilder.append( - "
"); - } else if ("image".equals(type)) { + if ("image".equals(type)) { if (element.has("imageData") && !element.get("imageData").asText().isEmpty()) { String imageData = element.get("imageData").asText(); // Ensure proper data URL format @@ -433,6 +445,9 @@ public class CustomerInvoiceService { } else if ("services.list".equals(variable)) { // Render services list as a table htmlBuilder.append(generateServicesTableHtml(mmWidth)); + } else if (text.contains("
")) { + // Multi-line text: render without nowrap so
tags work + htmlBuilder.append("").append(text).append(""); } else { // Wrap text in a span to prevent flexbox issues htmlBuilder.append("").append(text).append(""); @@ -640,7 +655,6 @@ public class CustomerInvoiceService { } int fontSize = element.has("fontSize") ? element.get("fontSize").asInt(14) : 14; - String fontStyle = element.has("fontStyle") ? element.get("fontStyle").asText("") : ""; String color = element.has("color") ? element.get("color").asText("#333333") : "#333333"; // Convert percentages to mm (A4 is 210mm x 297mm) @@ -653,22 +667,26 @@ public class CustomerInvoiceService { htmlBuilder.append("style='"); htmlBuilder.append("left:").append(String.format(java.util.Locale.US, "%.2f", mmX)).append("mm;"); htmlBuilder.append("top:").append(String.format(java.util.Locale.US, "%.2f", mmY)).append("mm;"); - htmlBuilder.append("width:").append(String.format(java.util.Locale.US, "%.2f", mmWidth)).append("mm;"); - htmlBuilder.append("height:").append(String.format(java.util.Locale.US, "%.2f", mmHeight)) - .append("mm;"); - htmlBuilder.append("font-size:").append(fontSize).append("pt;"); - htmlBuilder.append("line-height:").append(String.format(java.util.Locale.US, "%.2f", fontSize * 1.2)) - .append("pt;"); - htmlBuilder.append("color:").append(color).append(";"); - if (!fontStyle.isEmpty()) { - if (fontStyle.contains("bold")) - htmlBuilder.append("font-weight:bold;"); - } - // For services.list use block display - if ("services.list".equals(variable)) { - htmlBuilder.append("display:block;overflow:visible;padding:0;"); + if ("line".equals(type)) { + htmlBuilder.append("width:").append(String.format(java.util.Locale.US, "%.2f", mmWidth)).append("mm;"); + htmlBuilder.append("height:0;border-top:1px solid #333;"); + } else if ("vline".equals(type)) { + htmlBuilder.append("width:0;border-left:1px solid #333;"); + htmlBuilder.append("height:").append(String.format(java.util.Locale.US, "%.2f", mmHeight)).append("mm;"); } else { - htmlBuilder.append("display:flex;align-items:center;"); + htmlBuilder.append("width:").append(String.format(java.util.Locale.US, "%.2f", mmWidth)).append("mm;"); + htmlBuilder.append("height:").append(String.format(java.util.Locale.US, "%.2f", mmHeight)) + .append("mm;"); + htmlBuilder.append("font-size:").append(fontSize).append("pt;"); + htmlBuilder.append("line-height:").append(String.format(java.util.Locale.US, "%.2f", fontSize * 1.2)) + .append("pt;"); + htmlBuilder.append("color:").append(color).append(";"); + // For services.list use block display + if ("services.list".equals(variable)) { + htmlBuilder.append("display:block;overflow:visible;padding:0;"); + } else { + htmlBuilder.append("display:flex;align-items:center;"); + } } htmlBuilder.append("'"); htmlBuilder.append(">"); @@ -695,14 +713,13 @@ public class CustomerInvoiceService { if (text != null) { text = text.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """) .replace("'", "'"); + // Convert newlines to
for multi-line elements (e.g. customer address) + text = text.replace("\n", "
"); } else { text = ""; } - if ("line".equals(type)) { - htmlBuilder.append( - "
"); - } else if ("image".equals(type)) { + if ("image".equals(type)) { if (element.has("imageData") && !element.get("imageData").asText().isEmpty()) { String imageData = element.get("imageData").asText(); if (!imageData.startsWith("data:")) { @@ -720,6 +737,9 @@ public class CustomerInvoiceService { } else if ("services.list".equals(variable)) { // Render services list as a table with actual data htmlBuilder.append(generateServicesTableHtmlWithData(mmWidth, variables)); + } else if (text.contains("
")) { + // Multi-line text: render without nowrap so
tags work + htmlBuilder.append("").append(text).append(""); } else { htmlBuilder.append("").append(text).append(""); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3b9d1d9..1874462 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -6,6 +6,7 @@ spring.profiles.active=dev # Logging configuration logging.level.org.atmosphere=warn +logging.level.com.vaadin.flow.server.communication.PushAtmosphereHandler=off logging.level.de.assecutor.votianlt=INFO logging.level.de.assecutor.votianlt.controller.MessageController=DEBUG logging.level.de.assecutor.votianlt.config.MongoConfig=DEBUG diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 7615ff3..309bff2 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -36,8 +36,14 @@ profile.basicdata=Stammdaten profile.map=Karte profile.invoicecreation=Rechnungserstellung profile.settings=Einstellungen +profile.settings.digitalprocess=Digitale Abwicklung +profile.settings.digitalprocess.info=Aufträge werden digital über die App abgewickelt +profile.settings.locateappuser=App-Nutzer orten +profile.settings.locateappuser.info=Standort der App-Nutzer wird regelmäßig übertragen profile.account=Konto profile.security=Sicherheit +profile.security.twofactor=Zwei-Faktor-Authentifizierung +profile.security.twofactor.info=Beim Anmelden wird ein zusätzlicher Code per E-Mail versendet profile.services=Leistungskatalog profile.saved=Profil gespeichert profile.save.error=Fehler beim Speichern: {0} @@ -53,6 +59,7 @@ settings.twofactorinfo=Bei Aktivierung wird bei jeder Anmeldung ein Code per E-M # Profile Billing profile.billing.enabled=Rechnungslegung über votianLT +profile.billing.prefix=Rechnungspräfix # Profile Validation profile.validation.company=Firma ist ein Pflichtfeld @@ -106,6 +113,7 @@ profile.invoice.element.company=Firmeninfo profile.invoice.element.amount=Betrag profile.invoice.element.line=Linie profile.invoice.element.image=Bild +profile.invoice.element.invoicenumber=Rechnungsnummer profile.invoice.properties=Eigenschaften profile.invoice.properties.info=Klicken Sie auf ein Element im Canvas, um dessen Eigenschaften zu bearbeiten. profile.invoice.type=Typ @@ -655,6 +663,21 @@ myinvoices.bank.iban=IBAN myinvoices.recipient.name=Kunde myinvoices.recipient.department= myinvoices.item.description=Position: {0} +myinvoices.card.open=Offene Rechnungen +myinvoices.card.bank=Bankverbindung +myinvoices.bank.reference=Verwendungszweck +myinvoices.section.title=Alle Rechnungen +myinvoices.filter.pagesize=Einträge pro Seite +myinvoices.filter.search=Suche +myinvoices.filter.search.placeholder=Rechnungsnummer suchen... +myinvoices.column.status=Status +myinvoices.column.number=Nummer +myinvoices.column.date=Datum +myinvoices.column.amount=Betrag +myinvoices.empty.title=Keine Rechnungen +myinvoices.empty.desc=Es wurden keine Rechnungen gefunden. +myinvoices.button.prev=Zurück +myinvoices.button.next=Weiter # App User appuser.title=App-Nutzer @@ -811,6 +834,7 @@ invoicegenerator.upload.success=Bild erfolgreich hochgeladen invoicegenerator.upload.error=Fehler beim Hochladen: {0} invoicegenerator.file.rejected=Datei abgelehnt: {0} invoicegenerator.properties.select.info=Klicken Sie auf ein Element im Canvas, um dessen Eigenschaften zu bearbeiten. +invoicegenerator.template.vline=Vertikale Linie # CSV Export csv.header.customer=Auftraggeber diff --git a/src/main/resources/messages_ee.properties b/src/main/resources/messages_ee.properties index 26725d1..2530779 100644 --- a/src/main/resources/messages_ee.properties +++ b/src/main/resources/messages_ee.properties @@ -36,8 +36,14 @@ profile.basicdata=Põhiandmed profile.map=Kaart profile.invoicecreation=Arve loomine profile.settings=Seaded +profile.settings.digitalprocess=Digitaalne töötlus +profile.settings.digitalprocess.info=Tellimused töödeldakse rakenduse kaudu digitaalselt +profile.settings.locateappuser=Leia rakenduse kasutaja +profile.settings.locateappuser.info=Rakenduse kasutajate asukoht edastatakse regulaarselt profile.account=Konto profile.security=Turvalisus +profile.security.twofactor=Kahefaktoriline autentimine +profile.security.twofactor.info=Sisselogimisel saadetakse e-postiga täiendav kood profile.services=Teenuste kataloog profile.saved=Profiil salvestatud profile.save.error=Viga salvestamisel: {0} @@ -189,6 +195,32 @@ register.notification.failed=Registreerimine ebaõnnestus: {0} # CTA Button cta.freetest=Proovi tasuta + +# Profile Billing +profile.billing.prefix=Arve eesliide +profile.invoice.element.invoicenumber=Arve number + +# My Invoices +myinvoices.title=Minu arved +myinvoices.hint.noopen=Teil ei ole avatud arveid. Kõik arved on tasutud. +myinvoices.bank.institute=Pank +myinvoices.bank.beneficiary=Saaja +myinvoices.bank.iban=IBAN +myinvoices.card.open=Avatud arved +myinvoices.card.bank=Pangaandmed +myinvoices.bank.reference=Selgitus +myinvoices.section.title=Kõik arved +myinvoices.filter.pagesize=Kirjeid lehel +myinvoices.filter.search=Otsing +myinvoices.filter.search.placeholder=Otsi arve numbrit... +myinvoices.column.status=Staatus +myinvoices.column.number=Number +myinvoices.column.date=Kuupäev +myinvoices.column.amount=Summa +myinvoices.empty.title=Arveid pole +myinvoices.empty.desc=Arveid ei leitud. +myinvoices.button.prev=Eelmine +myinvoices.button.next=Järgmine src/main/resources/messages_lv.properties diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index cea1b6b..50e8c3f 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -36,8 +36,14 @@ profile.basicdata=Basic Data profile.map=Map profile.invoicecreation=Invoice Creation profile.settings=Settings +profile.settings.digitalprocess=Digital Processing +profile.settings.digitalprocess.info=Jobs are processed digitally via the app +profile.settings.locateappuser=Locate App User +profile.settings.locateappuser.info=Location of app users is regularly transmitted profile.account=Account profile.security=Security +profile.security.twofactor=Two-Factor Authentication +profile.security.twofactor.info=An additional code is sent by email when logging in profile.services=Service Catalog profile.saved=Profile saved profile.save.error=Error saving: {0} @@ -53,6 +59,7 @@ settings.twofactorinfo=When enabled, a code will be sent via email for each logi # Profile Billing profile.billing.enabled=Billing via votianLT +profile.billing.prefix=Invoice Prefix # Profile Validation profile.validation.company=Company is a required field @@ -106,6 +113,7 @@ profile.invoice.element.company=Company Info profile.invoice.element.amount=Amount profile.invoice.element.line=Line profile.invoice.element.image=Image +profile.invoice.element.invoicenumber=Invoice Number profile.invoice.properties=Properties profile.invoice.properties.info=Click on an element in the canvas to edit its properties profile.invoice.type=Type @@ -655,6 +663,21 @@ myinvoices.bank.iban=IBAN myinvoices.recipient.name=Customer myinvoices.recipient.department= myinvoices.item.description=Item: {0} +myinvoices.card.open=Open Invoices +myinvoices.card.bank=Bank Account +myinvoices.bank.reference=Reference +myinvoices.section.title=All Invoices +myinvoices.filter.pagesize=Entries per page +myinvoices.filter.search=Search +myinvoices.filter.search.placeholder=Search invoice number... +myinvoices.column.status=Status +myinvoices.column.number=Number +myinvoices.column.date=Date +myinvoices.column.amount=Amount +myinvoices.empty.title=No Invoices +myinvoices.empty.desc=No invoices were found. +myinvoices.button.prev=Previous +myinvoices.button.next=Next # App User appuser.title=App Users diff --git a/src/main/resources/messages_es.properties b/src/main/resources/messages_es.properties index b9752f4..bf8cafb 100644 --- a/src/main/resources/messages_es.properties +++ b/src/main/resources/messages_es.properties @@ -36,8 +36,14 @@ profile.basicdata=Datos Básicos profile.map=Mapa profile.invoicecreation=Creación de Factura profile.settings=Configuración +profile.settings.digitalprocess=Procesamiento digital +profile.settings.digitalprocess.info=Los pedidos se procesan digitalmente a través de la aplicación +profile.settings.locateappuser=Localizar usuario de la aplicación +profile.settings.locateappuser.info=La ubicación de los usuarios se transmite regularmente profile.account=Cuenta profile.security=Seguridad +profile.security.twofactor=Autenticación de dos factores +profile.security.twofactor.info=Se envía un código adicional por correo al iniciar sesión profile.services=Catálogo de Servicios profile.saved=Perfil guardado profile.save.error=Error al guardar: {0} @@ -53,6 +59,7 @@ settings.twofactorinfo=Cuando está activado, se enviará un código por correo # Profile Billing profile.billing.enabled=Facturación a través de votianLT +profile.billing.prefix=Prefijo de factura # Profile Validation profile.validation.company=La empresa es un campo obligatorio @@ -106,6 +113,7 @@ profile.invoice.element.company=Información de la Empresa profile.invoice.element.amount=Cantidad profile.invoice.element.line=Línea profile.invoice.element.image=Imagen +profile.invoice.element.invoicenumber=Número de factura profile.invoice.properties=Propiedades profile.invoice.properties.info=Haga clic en un elemento del lienzo para editar sus propiedades profile.invoice.type=Tipo @@ -655,6 +663,21 @@ myinvoices.bank.iban=IBAN myinvoices.recipient.name=Cliente myinvoices.recipient.department= myinvoices.item.description=Artículo: {0} +myinvoices.card.open=Facturas abiertas +myinvoices.card.bank=Datos bancarios +myinvoices.bank.reference=Referencia +myinvoices.section.title=Todas las facturas +myinvoices.filter.pagesize=Entradas por página +myinvoices.filter.search=Búsqueda +myinvoices.filter.search.placeholder=Buscar número de factura... +myinvoices.column.status=Estado +myinvoices.column.number=Número +myinvoices.column.date=Fecha +myinvoices.column.amount=Importe +myinvoices.empty.title=Sin facturas +myinvoices.empty.desc=No se encontraron facturas. +myinvoices.button.prev=Anterior +myinvoices.button.next=Siguiente # App User appuser.title=Usuarios de App diff --git a/src/main/resources/messages_fr.properties b/src/main/resources/messages_fr.properties index a7e0fd9..4f2b037 100644 --- a/src/main/resources/messages_fr.properties +++ b/src/main/resources/messages_fr.properties @@ -36,8 +36,14 @@ profile.basicdata=Données de Base profile.map=Carte profile.invoicecreation=Création de Facture profile.settings=Paramètres +profile.settings.digitalprocess=Traitement numérique +profile.settings.digitalprocess.info=Les commandes sont traitées numériquement via l'application +profile.settings.locateappuser=Localiser l'utilisateur de l'application +profile.settings.locateappuser.info=La localisation des utilisateurs est transmise régulièrement profile.account=Compte profile.security=Sécurité +profile.security.twofactor=Authentification à deux facteurs +profile.security.twofactor.info=Un code supplémentaire est envoyé par e-mail lors de la connexion profile.services=Catalogue de Services profile.saved=Profil enregistré profile.save.error=Erreur lors de l'enregistrement : {0} @@ -53,6 +59,7 @@ settings.twofactorinfo=Une fois activé, un code sera envoyé par email à chaqu # Profile Billing profile.billing.enabled=Facturation via votianLT +profile.billing.prefix=Préfixe de facture # Profile Validation profile.validation.company=L'entreprise est un champ obligatoire @@ -106,6 +113,7 @@ profile.invoice.element.company=Infos Entreprise profile.invoice.element.amount=Montant profile.invoice.element.line=Ligne profile.invoice.element.image=Image +profile.invoice.element.invoicenumber=Numéro de facture profile.invoice.properties=Propriétés profile.invoice.properties.info=Cliquez sur un élément dans le canevas pour modifier ses propriétés profile.invoice.type=Type @@ -655,6 +663,21 @@ myinvoices.bank.iban=IBAN myinvoices.recipient.name=Client myinvoices.recipient.department= myinvoices.item.description=Article : {0} +myinvoices.card.open=Factures ouvertes +myinvoices.card.bank=Coordonnées bancaires +myinvoices.bank.reference=Référence +myinvoices.section.title=Toutes les factures +myinvoices.filter.pagesize=Entrées par page +myinvoices.filter.search=Recherche +myinvoices.filter.search.placeholder=Rechercher un numéro de facture... +myinvoices.column.status=Statut +myinvoices.column.number=Numéro +myinvoices.column.date=Date +myinvoices.column.amount=Montant +myinvoices.empty.title=Aucune facture +myinvoices.empty.desc=Aucune facture trouvée. +myinvoices.button.prev=Précédent +myinvoices.button.next=Suivant # App User appuser.title=Utilisateurs d'App diff --git a/src/main/resources/messages_lt.properties b/src/main/resources/messages_lt.properties index 3819ec9..6118132 100644 --- a/src/main/resources/messages_lt.properties +++ b/src/main/resources/messages_lt.properties @@ -36,8 +36,14 @@ profile.basicdata=Pagrindiniai duomenys profile.map=Žemėlapis profile.invoicecreation=Sąskaitos kūrimas profile.settings=Nustatymai +profile.settings.digitalprocess=Skaitmeninis apdorojimas +profile.settings.digitalprocess.info=Užsakymai apdorojami skaitmeniškai per programėlę +profile.settings.locateappuser=Rasti programėlės naudotoją +profile.settings.locateappuser.info=Programėlės naudotojų vieta reguliariai perduodama profile.account=Paskyra profile.security=Saugumas +profile.security.twofactor=Dviejų veiksnių autentifikavimas +profile.security.twofactor.info=Prisijungiant el. paštu siunčiamas papildomas kodas profile.services=Paslaugų katalogas profile.saved=Profilis išsaugotas profile.save.error=Klaida išsaugant: {0} @@ -188,4 +194,30 @@ register.notification.success=Registracija sėkminga. Prašome prisijungti. register.notification.failed=Registracijos klaida: {0} # CTA Button -cta.freetest=Išbandykite nemokamai \ No newline at end of file +cta.freetest=Išbandykite nemokamai + +# Profile Billing +profile.billing.prefix=Sąskaitos prefiksas +profile.invoice.element.invoicenumber=Sąskaitos numeris + +# My Invoices +myinvoices.title=Mano sąskaitos +myinvoices.hint.noopen=Neturite atvirų sąskaitų. Visos sąskaitos apmokėtos. +myinvoices.bank.institute=Bankas +myinvoices.bank.beneficiary=Gavėjas +myinvoices.bank.iban=IBAN +myinvoices.card.open=Atidarytos sąskaitos +myinvoices.card.bank=Banko duomenys +myinvoices.bank.reference=Mokėjimo paskirtis +myinvoices.section.title=Visos sąskaitos +myinvoices.filter.pagesize=Įrašų per puslapį +myinvoices.filter.search=Paieška +myinvoices.filter.search.placeholder=Ieškoti sąskaitos numerio... +myinvoices.column.status=Statusas +myinvoices.column.number=Numeris +myinvoices.column.date=Data +myinvoices.column.amount=Suma +myinvoices.empty.title=Sąskaitų nėra +myinvoices.empty.desc=Sąskaitų nerasta. +myinvoices.button.prev=Ankstesnis +myinvoices.button.next=Kitas \ No newline at end of file diff --git a/src/main/resources/messages_lv.properties b/src/main/resources/messages_lv.properties index d76311e..76d5850 100644 --- a/src/main/resources/messages_lv.properties +++ b/src/main/resources/messages_lv.properties @@ -36,8 +36,14 @@ profile.basicdata=Pamatdati profile.map=Karte profile.invoicecreation=Rēķina izveide profile.settings=Iestatījumi +profile.settings.digitalprocess=Digitālā apstrāde +profile.settings.digitalprocess.info=Pasūtījumi tiek apstrādāti digitāli, izmantojot lietotni +profile.settings.locateappuser=Atrast lietotnes lietotāju +profile.settings.locateappuser.info=Lietotnes lietotāju atrašanās vieta tiek regulāri pārsūtīta profile.account=Konts profile.security=Drošība +profile.security.twofactor=Divu faktoru autentifikācija +profile.security.twofactor.info=Pierakstoties tiek nosūtīts papildu kods uz e-pastu profile.services=Pakalpojumu katalogs profile.saved=Profils saglabāts profile.save.error=Kļūda saglabājot: {0} @@ -188,4 +194,30 @@ register.notification.success=Reģistrācija veiksmīga. Lūdzu, pieteikties. register.notification.failed=Reģistrācijas kļūda: {0} # CTA Button -cta.freetest=Izmēģiniet bez maksas \ No newline at end of file +cta.freetest=Izmēģiniet bez maksas + +# Profile Billing +profile.billing.prefix=Rēķina prefikss +profile.invoice.element.invoicenumber=Rēķina numurs + +# My Invoices +myinvoices.title=Mani rēķini +myinvoices.hint.noopen=Jums nav atvērtu rēķinu. Visi rēķini ir apmaksāti. +myinvoices.bank.institute=Banka +myinvoices.bank.beneficiary=Saņēmējs +myinvoices.bank.iban=IBAN +myinvoices.card.open=Atvērtie rēķini +myinvoices.card.bank=Bankas dati +myinvoices.bank.reference=Maksājuma mērķis +myinvoices.section.title=Visi rēķini +myinvoices.filter.pagesize=Ieraksti lapā +myinvoices.filter.search=Meklēt +myinvoices.filter.search.placeholder=Meklēt rēķina numuru... +myinvoices.column.status=Statuss +myinvoices.column.number=Numurs +myinvoices.column.date=Datums +myinvoices.column.amount=Summa +myinvoices.empty.title=Nav rēķinu +myinvoices.empty.desc=Rēķini nav atrasti. +myinvoices.button.prev=Iepriekšējais +myinvoices.button.next=Nākamais \ No newline at end of file diff --git a/src/main/resources/messages_pl.properties b/src/main/resources/messages_pl.properties index 3ff638b..6ecb9be 100644 --- a/src/main/resources/messages_pl.properties +++ b/src/main/resources/messages_pl.properties @@ -36,8 +36,14 @@ profile.basicdata=Dane podstawowe profile.map=Mapa profile.invoicecreation=Tworzenie faktury profile.settings=Ustawienia +profile.settings.digitalprocess=Przetwarzanie cyfrowe +profile.settings.digitalprocess.info=Zlecenia są przetwarzane cyfrowo przez aplikację +profile.settings.locateappuser=Lokalizuj użytkownika aplikacji +profile.settings.locateappuser.info=Lokalizacja użytkowników jest regularnie przesyłana profile.account=Konto profile.security=Bezpieczeństwo +profile.security.twofactor=Uwierzytelnianie dwuskładnikowe +profile.security.twofactor.info=Dodatkowy kod jest wysyłany e-mailem przy logowaniu profile.services=Katalog usług profile.saved=Profil zapisany profile.save.error=Błąd podczas zapisywania: {0} @@ -191,4 +197,30 @@ register.notification.success=Rejestracja zakończona sukcesem. Zaloguj się. register.notification.failed=Rejestracja nie powiodła się: {0} # CTA Button -cta.freetest=Wypróbuj teraz za darmo \ No newline at end of file +cta.freetest=Wypróbuj teraz za darmo + +# Profile Billing +profile.billing.prefix=Prefiks faktury +profile.invoice.element.invoicenumber=Numer faktury + +# My Invoices +myinvoices.title=Moje faktury +myinvoices.hint.noopen=Nie masz otwartych faktur. Wszystkie faktury są uregulowane. +myinvoices.bank.institute=Bank +myinvoices.bank.beneficiary=Odbiorca +myinvoices.bank.iban=IBAN +myinvoices.card.open=Otwarte faktury +myinvoices.card.bank=Dane bankowe +myinvoices.bank.reference=Tytuł przelewu +myinvoices.section.title=Wszystkie faktury +myinvoices.filter.pagesize=Wpisów na stronie +myinvoices.filter.search=Szukaj +myinvoices.filter.search.placeholder=Szukaj numeru faktury... +myinvoices.column.status=Status +myinvoices.column.number=Numer +myinvoices.column.date=Data +myinvoices.column.amount=Kwota +myinvoices.empty.title=Brak faktur +myinvoices.empty.desc=Nie znaleziono faktur. +myinvoices.button.prev=Poprzedni +myinvoices.button.next=Następny \ No newline at end of file diff --git a/src/main/resources/messages_ru.properties b/src/main/resources/messages_ru.properties index 5e85e4e..16aef01 100644 --- a/src/main/resources/messages_ru.properties +++ b/src/main/resources/messages_ru.properties @@ -36,8 +36,14 @@ profile.basicdata=Основные данные profile.map=Карта profile.invoicecreation=Создание счета profile.settings=Настройки +profile.settings.digitalprocess=Цифровая обработка +profile.settings.digitalprocess.info=Заказы обрабатываются в цифровом формате через приложение +profile.settings.locateappuser=Определить местоположение пользователя +profile.settings.locateappuser.info=Местоположение пользователей приложения регулярно передаётся profile.account=Аккаунт profile.security=Безопасность +profile.security.twofactor=Двухфакторная аутентификация +profile.security.twofactor.info=При входе на электронную почту отправляется дополнительный код profile.services=Каталог услуг profile.saved=Профиль сохранен profile.save.error=Ошибка сохранения: {0} @@ -211,4 +217,30 @@ register.notification.success=Регистрация прошла успешно register.notification.failed=Ошибка регистрации: {0} # CTA Button -cta.freetest=Попробуйте бесплатно \ No newline at end of file +cta.freetest=Попробуйте бесплатно + +# Profile Billing +profile.billing.prefix=Префикс счёта +profile.invoice.element.invoicenumber=Номер счёта + +# My Invoices +myinvoices.title=Мои счета +myinvoices.hint.noopen=У вас нет открытых счетов. Все счета оплачены. +myinvoices.bank.institute=Банк +myinvoices.bank.beneficiary=Получатель +myinvoices.bank.iban=IBAN +myinvoices.card.open=Открытые счета +myinvoices.card.bank=Банковские реквизиты +myinvoices.bank.reference=Назначение платежа +myinvoices.section.title=Все счета +myinvoices.filter.pagesize=Записей на странице +myinvoices.filter.search=Поиск +myinvoices.filter.search.placeholder=Поиск по номеру счёта... +myinvoices.column.status=Статус +myinvoices.column.number=Номер +myinvoices.column.date=Дата +myinvoices.column.amount=Сумма +myinvoices.empty.title=Нет счетов +myinvoices.empty.desc=Счета не найдены. +myinvoices.button.prev=Назад +myinvoices.button.next=Далее \ No newline at end of file diff --git a/src/main/resources/messages_tr.properties b/src/main/resources/messages_tr.properties index d84df0a..8da81ae 100644 --- a/src/main/resources/messages_tr.properties +++ b/src/main/resources/messages_tr.properties @@ -36,8 +36,14 @@ profile.basicdata=Temel Veriler profile.map=Harita profile.invoicecreation=Fatura Oluşturma profile.settings=Ayarlar +profile.settings.digitalprocess=Dijital İşlem +profile.settings.digitalprocess.info=Siparişler uygulama üzerinden dijital olarak işlenir +profile.settings.locateappuser=Uygulama Kullanıcısını Konumla +profile.settings.locateappuser.info=Uygulama kullanıcılarının konumu düzenli olarak iletilir profile.account=Hesap profile.security=Güvenlik +profile.security.twofactor=İki Faktörlü Kimlik Doğrulama +profile.security.twofactor.info=Giriş yaparken e-posta ile ek bir kod gönderilir profile.services=Hizmet Kataloğu profile.saved=Profil kaydedildi profile.save.error=Kaydetme hatası: {0} @@ -185,4 +191,30 @@ register.notification.success=Kayıt başarılı. Lütfen giriş yapın. register.notification.failed=Kayıt başarısız: {0} # CTA Button -cta.freetest=Şimdi ücretsiz dene \ No newline at end of file +cta.freetest=Şimdi ücretsiz dene + +# Profile Billing +profile.billing.prefix=Fatura ön eki +profile.invoice.element.invoicenumber=Fatura numarası + +# My Invoices +myinvoices.title=Faturalarım +myinvoices.hint.noopen=Açık faturanız yok. Tüm faturalar ödendi. +myinvoices.bank.institute=Banka +myinvoices.bank.beneficiary=Alıcı +myinvoices.bank.iban=IBAN +myinvoices.card.open=Açık Faturalar +myinvoices.card.bank=Banka Bilgileri +myinvoices.bank.reference=Referans +myinvoices.section.title=Tüm Faturalar +myinvoices.filter.pagesize=Sayfa başına giriş +myinvoices.filter.search=Ara +myinvoices.filter.search.placeholder=Fatura numarası ara... +myinvoices.column.status=Durum +myinvoices.column.number=Numara +myinvoices.column.date=Tarih +myinvoices.column.amount=Tutar +myinvoices.empty.title=Fatura Yok +myinvoices.empty.desc=Hiçbir fatura bulunamadı. +myinvoices.button.prev=Önceki +myinvoices.button.next=Sonraki \ No newline at end of file