feat: Rechnungsversand als signierte E-Rechnung mit Sammel-ZIP-Download, Abbruch bei fehlgeschlagener Validierung (HTTP 422)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -552,10 +552,42 @@ public class AdminCreateInvoicesView extends Main implements HasDynamicTitle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends each invoice as PDF attachment to the respective customer's email
|
* Sends the invoices as signed ZUGFeRD e-invoice (ZIP) to the respective
|
||||||
* address and reports how many mails were (not) sent.
|
* customers. First all signed ZIPs are created and cached; only when every
|
||||||
|
* ZIP could be created and passed the validation the mails are sent.
|
||||||
|
* Afterwards a combined ZIP containing all individual invoice ZIPs is
|
||||||
|
* offered as browser download.
|
||||||
*/
|
*/
|
||||||
private void sendInvoices(List<InvoicePreview> previews) {
|
private void sendInvoices(List<InvoicePreview> previews) {
|
||||||
|
// Phase 1: create and cache the signed ZIP of every invoice; abort
|
||||||
|
// without sending anything if a single one fails
|
||||||
|
Map<InvoicePreview, PdfToolService.SignedInvoice> signedZips = new LinkedHashMap<>();
|
||||||
|
for (InvoicePreview preview : previews) {
|
||||||
|
try {
|
||||||
|
signedZips.put(preview, pdfToolService.signInvoice(preview.pdf(), buildZugferdMetadata(preview)));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("Error creating ZUGFeRD e-invoice {} for batch send: {}", preview.invoiceNumber(),
|
||||||
|
ex.getMessage(), ex);
|
||||||
|
Notification
|
||||||
|
.show(getTranslation("admincreateinvoices.notification.zugferd.batcherror",
|
||||||
|
preview.invoiceNumber(), ex.getMessage()), 7000, Notification.Position.BOTTOM_CENTER)
|
||||||
|
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Invoices failing the Mustang validation stop the whole batch: no
|
||||||
|
// mail is sent as long as a single invoice is invalid
|
||||||
|
String invalidNumbers = signedZips.entrySet().stream().filter(entry -> !entry.getValue().valid())
|
||||||
|
.map(entry -> entry.getKey().invoiceNumber()).collect(java.util.stream.Collectors.joining(", "));
|
||||||
|
if (!invalidNumbers.isEmpty()) {
|
||||||
|
log.warn("Invoice batch send aborted, validation failed for: {}", invalidNumbers);
|
||||||
|
Notification
|
||||||
|
.show(getTranslation("admincreateinvoices.notification.zugferd.invalidsend", invalidNumbers),
|
||||||
|
7000, Notification.Position.BOTTOM_CENTER)
|
||||||
|
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String issuerName = "";
|
String issuerName = "";
|
||||||
try {
|
try {
|
||||||
issuerName = safe(systemCompanyProfileService.createSystemInvoiceData().getCompanyName());
|
issuerName = safe(systemCompanyProfileService.createSystemInvoiceData().getCompanyName());
|
||||||
@@ -564,9 +596,12 @@ public class AdminCreateInvoicesView extends Main implements HasDynamicTitle {
|
|||||||
}
|
}
|
||||||
String monthLabel = billingMonth.format(DateTimeFormatter.ofPattern("LLLL yyyy", getLocale()));
|
String monthLabel = billingMonth.format(DateTimeFormatter.ofPattern("LLLL yyyy", getLocale()));
|
||||||
|
|
||||||
|
// Phase 2: all ZIPs exist, send one mail per invoice with its ZIP
|
||||||
int sent = 0;
|
int sent = 0;
|
||||||
int failed = 0;
|
int failed = 0;
|
||||||
for (InvoicePreview preview : previews) {
|
for (Map.Entry<InvoicePreview, PdfToolService.SignedInvoice> entry : signedZips.entrySet()) {
|
||||||
|
InvoicePreview preview = entry.getKey();
|
||||||
|
PdfToolService.SignedInvoice signed = entry.getValue();
|
||||||
String email = preview.info().user().getEmail();
|
String email = preview.info().user().getEmail();
|
||||||
if (email == null || email.isBlank()) {
|
if (email == null || email.isBlank()) {
|
||||||
log.warn("Customer {} has no email address, invoice {} not sent",
|
log.warn("Customer {} has no email address, invoice {} not sent",
|
||||||
@@ -579,7 +614,7 @@ public class AdminCreateInvoicesView extends Main implements HasDynamicTitle {
|
|||||||
getTranslation("admincreateinvoices.mail.subject", preview.invoiceNumber()),
|
getTranslation("admincreateinvoices.mail.subject", preview.invoiceNumber()),
|
||||||
getTranslation("admincreateinvoices.mail.body", preview.invoiceNumber(), monthLabel,
|
getTranslation("admincreateinvoices.mail.body", preview.invoiceNumber(), monthLabel,
|
||||||
issuerName),
|
issuerName),
|
||||||
preview.pdf(), preview.invoiceNumber() + ".pdf");
|
signed.zip(), signed.fileName());
|
||||||
recordDispatch(preview, email);
|
recordDispatch(preview, email);
|
||||||
sent++;
|
sent++;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@@ -587,6 +622,22 @@ public class AdminCreateInvoicesView extends Main implements HasDynamicTitle {
|
|||||||
failed++;
|
failed++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase 3: bundle all individual invoice ZIPs and offer the download
|
||||||
|
if (signedZips.size() > 1) {
|
||||||
|
try {
|
||||||
|
String archiveName = "rechnungen-" + billingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"))
|
||||||
|
+ "-zugferd.zip";
|
||||||
|
triggerZipDownload(buildCombinedZip(signedZips.values()), archiveName);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("Error creating combined invoice ZIP: {}", ex.getMessage(), ex);
|
||||||
|
Notification
|
||||||
|
.show(getTranslation("admincreateinvoices.notification.zip.combined.error", ex.getMessage()),
|
||||||
|
7000, Notification.Position.BOTTOM_CENTER)
|
||||||
|
.addThemeVariants(NotificationVariant.LUMO_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sent > 0) {
|
if (sent > 0) {
|
||||||
grid.deselectAll();
|
grid.deselectAll();
|
||||||
grid.setItems(loadBillingInfos());
|
grid.setItems(loadBillingInfos());
|
||||||
@@ -748,11 +799,7 @@ public class AdminCreateInvoicesView extends Main implements HasDynamicTitle {
|
|||||||
try {
|
try {
|
||||||
PdfToolService.SignedInvoice signed = pdfToolService.signInvoice(preview.pdf(),
|
PdfToolService.SignedInvoice signed = pdfToolService.signInvoice(preview.pdf(),
|
||||||
buildZugferdMetadata(preview));
|
buildZugferdMetadata(preview));
|
||||||
String base64Zip = Base64.getEncoder().encodeToString(signed.zip());
|
triggerZipDownload(signed.zip(), signed.fileName());
|
||||||
getElement().executeJs("const link = document.createElement('a');"
|
|
||||||
+ "link.href = 'data:application/zip;base64," + base64Zip + "';" + "link.download = '"
|
|
||||||
+ signed.fileName().replace("'", "") + "';"
|
|
||||||
+ "document.body.appendChild(link); link.click(); document.body.removeChild(link);");
|
|
||||||
if (signed.valid()) {
|
if (signed.valid()) {
|
||||||
Notification
|
Notification
|
||||||
.show(getTranslation("admincreateinvoices.notification.zugferd.created",
|
.show(getTranslation("admincreateinvoices.notification.zugferd.created",
|
||||||
@@ -773,6 +820,32 @@ public class AdminCreateInvoicesView extends Main implements HasDynamicTitle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Packs the individual invoice ZIPs into one combined ZIP so all sent
|
||||||
|
* e-invoices can be archived with a single download.
|
||||||
|
*/
|
||||||
|
private byte[] buildCombinedZip(java.util.Collection<PdfToolService.SignedInvoice> signedInvoices)
|
||||||
|
throws java.io.IOException {
|
||||||
|
java.io.ByteArrayOutputStream buffer = new java.io.ByteArrayOutputStream();
|
||||||
|
try (java.util.zip.ZipOutputStream zipStream = new java.util.zip.ZipOutputStream(buffer)) {
|
||||||
|
for (PdfToolService.SignedInvoice signed : signedInvoices) {
|
||||||
|
zipStream.putNextEntry(new java.util.zip.ZipEntry(signed.fileName()));
|
||||||
|
zipStream.write(signed.zip());
|
||||||
|
zipStream.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Offers the given ZIP bytes as browser download. */
|
||||||
|
private void triggerZipDownload(byte[] zip, String fileName) {
|
||||||
|
String base64Zip = Base64.getEncoder().encodeToString(zip);
|
||||||
|
getElement().executeJs("const link = document.createElement('a');"
|
||||||
|
+ "link.href = 'data:application/zip;base64," + base64Zip + "';" + "link.download = '"
|
||||||
|
+ fileName.replace("'", "") + "';"
|
||||||
|
+ "document.body.appendChild(link); link.click(); document.body.removeChild(link);");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the EN16931 metadata for the PDF Tool from the billing data: the
|
* Builds the EN16931 metadata for the PDF Tool from the billing data: the
|
||||||
* system operator as sender, the customer as recipient and the billed
|
* system operator as sender, the customer as recipient and the billed
|
||||||
|
|||||||
@@ -65,7 +65,10 @@ public class PdfToolService {
|
|||||||
/**
|
/**
|
||||||
* Converts the given invoice PDF into a ZUGFeRD e-invoice. Returns the ZIP
|
* Converts the given invoice PDF into a ZUGFeRD e-invoice. Returns the ZIP
|
||||||
* provided by the PDF Tool; throws with the tool's error message if the
|
* provided by the PDF Tool; throws with the tool's error message if the
|
||||||
* conversion is rejected (e.g. incomplete metadata).
|
* conversion is rejected (e.g. incomplete metadata). A failed Mustang
|
||||||
|
* validation is reported by the tool as HTTP 422 but still carries the ZIP
|
||||||
|
* (including the validation report) in the body; it is returned as a
|
||||||
|
* {@link SignedInvoice} with {@code valid=false} instead of throwing.
|
||||||
*/
|
*/
|
||||||
public SignedInvoice signInvoice(byte[] pdfBytes, InvoiceMetadata metadata) throws Exception {
|
public SignedInvoice signInvoice(byte[] pdfBytes, InvoiceMetadata metadata) throws Exception {
|
||||||
String metadataJson = objectMapper.writeValueAsString(metadata);
|
String metadataJson = objectMapper.writeValueAsString(metadata);
|
||||||
@@ -79,23 +82,30 @@ public class PdfToolService {
|
|||||||
}, MediaType.APPLICATION_PDF);
|
}, MediaType.APPLICATION_PDF);
|
||||||
body.part("metadata", metadataJson, MediaType.APPLICATION_JSON);
|
body.part("metadata", metadataJson, MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
ResponseEntity<byte[]> response;
|
|
||||||
try {
|
try {
|
||||||
response = restClient.post().uri("/api/invoices/sign").contentType(MediaType.MULTIPART_FORM_DATA)
|
ResponseEntity<byte[]> response = restClient.post().uri("/api/invoices/sign")
|
||||||
.body(body.build()).retrieve().toEntity(byte[].class);
|
.contentType(MediaType.MULTIPART_FORM_DATA).body(body.build()).retrieve()
|
||||||
|
.toEntity(byte[].class);
|
||||||
|
return toSignedInvoice(response.getBody(), response.getHeaders(), metadata);
|
||||||
} catch (RestClientResponseException ex) {
|
} catch (RestClientResponseException ex) {
|
||||||
|
if (ex.getStatusCode().value() == 422 && ex.getResponseBodyAsByteArray().length > 0) {
|
||||||
|
return toSignedInvoice(ex.getResponseBodyAsByteArray(), ex.getResponseHeaders(), metadata);
|
||||||
|
}
|
||||||
throw new IllegalStateException(extractErrorMessage(ex), ex);
|
throw new IllegalStateException(extractErrorMessage(ex), ex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
byte[] zip = response.getBody();
|
/** Builds the result from the response ZIP, file name and validation header. */
|
||||||
|
private SignedInvoice toSignedInvoice(byte[] zip, org.springframework.http.HttpHeaders headers,
|
||||||
|
InvoiceMetadata metadata) {
|
||||||
if (zip == null || zip.length == 0) {
|
if (zip == null || zip.length == 0) {
|
||||||
throw new IllegalStateException("PDF Tool returned an empty response");
|
throw new IllegalStateException("PDF Tool returned an empty response");
|
||||||
}
|
}
|
||||||
String fileName = response.getHeaders().getContentDisposition().getFilename();
|
String fileName = headers != null ? headers.getContentDisposition().getFilename() : null;
|
||||||
if (fileName == null || fileName.isBlank()) {
|
if (fileName == null || fileName.isBlank()) {
|
||||||
fileName = metadata.invoiceNumber() + "-zugferd.zip";
|
fileName = metadata.invoiceNumber() + "-zugferd.zip";
|
||||||
}
|
}
|
||||||
boolean valid = Boolean.parseBoolean(response.getHeaders().getFirst(VALIDATION_HEADER));
|
boolean valid = headers != null && Boolean.parseBoolean(headers.getFirst(VALIDATION_HEADER));
|
||||||
return new SignedInvoice(zip, fileName, valid);
|
return new SignedInvoice(zip, fileName, valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1153,3 +1153,6 @@ admincreateinvoices.notification.zugferd.created=E-Rechnung {0} erstellt
|
|||||||
admincreateinvoices.notification.zugferd.invalid=E-Rechnung erstellt, aber die Validierung ist fehlgeschlagen. Details im Prüfbericht in der ZIP-Datei.
|
admincreateinvoices.notification.zugferd.invalid=E-Rechnung erstellt, aber die Validierung ist fehlgeschlagen. Details im Prüfbericht in der ZIP-Datei.
|
||||||
admincreateinvoices.notification.zugferd.error=Fehler beim Erstellen der E-Rechnung: {0}
|
admincreateinvoices.notification.zugferd.error=Fehler beim Erstellen der E-Rechnung: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=Keine abrechenbaren Positionen für die E-Rechnung vorhanden
|
admincreateinvoices.notification.zugferd.nopositions=Keine abrechenbaren Positionen für die E-Rechnung vorhanden
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=E-Rechnung {0} konnte nicht erstellt werden, es wurden keine Rechnungen versendet: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=Validierung fehlgeschlagen für: {0}. Es wurden keine Rechnungen versendet.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Fehler beim Erstellen der Sammel-ZIP-Datei: {0}
|
||||||
|
|||||||
@@ -983,3 +983,6 @@ admincreateinvoices.notification.zugferd.created=E-arve {0} loodud
|
|||||||
admincreateinvoices.notification.zugferd.invalid=E-arve on loodud, kuid valideerimine ebaõnnestus. Üksikasjad on ZIP-failis olevas valideerimisaruandes.
|
admincreateinvoices.notification.zugferd.invalid=E-arve on loodud, kuid valideerimine ebaõnnestus. Üksikasjad on ZIP-failis olevas valideerimisaruandes.
|
||||||
admincreateinvoices.notification.zugferd.error=Viga e-arve loomisel: {0}
|
admincreateinvoices.notification.zugferd.error=Viga e-arve loomisel: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=E-arve jaoks puuduvad arveldatavad positsioonid
|
admincreateinvoices.notification.zugferd.nopositions=E-arve jaoks puuduvad arveldatavad positsioonid
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=E-arvet {0} ei õnnestunud luua, ühtegi arvet ei saadetud: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=Valideerimine ebaõnnestus: {0}. Ühtegi arvet ei saadetud.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Viga koond-ZIP-faili loomisel: {0}
|
||||||
|
|||||||
@@ -1153,3 +1153,6 @@ admincreateinvoices.notification.zugferd.created=E-invoice {0} created
|
|||||||
admincreateinvoices.notification.zugferd.invalid=E-invoice created, but validation failed. See the validation report in the ZIP file.
|
admincreateinvoices.notification.zugferd.invalid=E-invoice created, but validation failed. See the validation report in the ZIP file.
|
||||||
admincreateinvoices.notification.zugferd.error=Error creating the e-invoice: {0}
|
admincreateinvoices.notification.zugferd.error=Error creating the e-invoice: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=No billable positions available for the e-invoice
|
admincreateinvoices.notification.zugferd.nopositions=No billable positions available for the e-invoice
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=E-invoice {0} could not be created, no invoices were sent: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=Validation failed for: {0}. No invoices were sent.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Error creating the combined ZIP file: {0}
|
||||||
|
|||||||
@@ -1084,3 +1084,6 @@ admincreateinvoices.notification.zugferd.created=Factura electrónica {0} creada
|
|||||||
admincreateinvoices.notification.zugferd.invalid=Factura electrónica creada, pero la validación ha fallado. Consulte el informe de validación en el archivo ZIP.
|
admincreateinvoices.notification.zugferd.invalid=Factura electrónica creada, pero la validación ha fallado. Consulte el informe de validación en el archivo ZIP.
|
||||||
admincreateinvoices.notification.zugferd.error=Error al crear la factura electrónica: {0}
|
admincreateinvoices.notification.zugferd.error=Error al crear la factura electrónica: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=No hay posiciones facturables disponibles para la factura electrónica
|
admincreateinvoices.notification.zugferd.nopositions=No hay posiciones facturables disponibles para la factura electrónica
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=No se pudo crear la factura electrónica {0}, no se envió ninguna factura: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=La validación falló para: {0}. No se envió ninguna factura.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Error al crear el archivo ZIP combinado: {0}
|
||||||
|
|||||||
@@ -1084,3 +1084,6 @@ admincreateinvoices.notification.zugferd.created=Facture électronique {0} cré
|
|||||||
admincreateinvoices.notification.zugferd.invalid=Facture électronique créée, mais la validation a échoué. Détails dans le rapport de validation du fichier ZIP.
|
admincreateinvoices.notification.zugferd.invalid=Facture électronique créée, mais la validation a échoué. Détails dans le rapport de validation du fichier ZIP.
|
||||||
admincreateinvoices.notification.zugferd.error=Erreur lors de la création de la facture électronique : {0}
|
admincreateinvoices.notification.zugferd.error=Erreur lors de la création de la facture électronique : {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=Aucune position facturable disponible pour la facture électronique
|
admincreateinvoices.notification.zugferd.nopositions=Aucune position facturable disponible pour la facture électronique
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=La facture électronique {0} n''a pas pu être créée, aucune facture n''a été envoyée : {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=La validation a échoué pour : {0}. Aucune facture n''a été envoyée.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Erreur lors de la création du fichier ZIP combiné : {0}
|
||||||
|
|||||||
@@ -1086,3 +1086,6 @@ admincreateinvoices.notification.zugferd.created=E. sąskaita {0} sukurta
|
|||||||
admincreateinvoices.notification.zugferd.invalid=E. sąskaita sukurta, tačiau patikra nepavyko. Išsami informacija patikros ataskaitoje ZIP faile.
|
admincreateinvoices.notification.zugferd.invalid=E. sąskaita sukurta, tačiau patikra nepavyko. Išsami informacija patikros ataskaitoje ZIP faile.
|
||||||
admincreateinvoices.notification.zugferd.error=Klaida kuriant e. sąskaitą: {0}
|
admincreateinvoices.notification.zugferd.error=Klaida kuriant e. sąskaitą: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=E. sąskaitai nėra apmokestinamų pozicijų
|
admincreateinvoices.notification.zugferd.nopositions=E. sąskaitai nėra apmokestinamų pozicijų
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=Nepavyko sukurti e. sąskaitos {0}, sąskaitos nebuvo išsiųstos: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=Patikrinimas nepavyko: {0}. Sąskaitos nebuvo išsiųstos.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Klaida kuriant bendrą ZIP failą: {0}
|
||||||
|
|||||||
@@ -1084,3 +1084,6 @@ admincreateinvoices.notification.zugferd.created=E-rēķins {0} izveidots
|
|||||||
admincreateinvoices.notification.zugferd.invalid=E-rēķins izveidots, bet validācija neizdevās. Detaļas skatiet validācijas atskaitē ZIP failā.
|
admincreateinvoices.notification.zugferd.invalid=E-rēķins izveidots, bet validācija neizdevās. Detaļas skatiet validācijas atskaitē ZIP failā.
|
||||||
admincreateinvoices.notification.zugferd.error=Kļūda, veidojot e-rēķinu: {0}
|
admincreateinvoices.notification.zugferd.error=Kļūda, veidojot e-rēķinu: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=E-rēķinam nav pieejamu norēķinu pozīciju
|
admincreateinvoices.notification.zugferd.nopositions=E-rēķinam nav pieejamu norēķinu pozīciju
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=Neizdevās izveidot e-rēķinu {0}, rēķini netika nosūtīti: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=Validācija neizdevās: {0}. Rēķini netika nosūtīti.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Kļūda, veidojot apvienoto ZIP failu: {0}
|
||||||
|
|||||||
@@ -1084,3 +1084,6 @@ admincreateinvoices.notification.zugferd.created=Utworzono e-fakturę {0}
|
|||||||
admincreateinvoices.notification.zugferd.invalid=E-faktura została utworzona, ale walidacja nie powiodła się. Szczegóły w raporcie walidacji w pliku ZIP.
|
admincreateinvoices.notification.zugferd.invalid=E-faktura została utworzona, ale walidacja nie powiodła się. Szczegóły w raporcie walidacji w pliku ZIP.
|
||||||
admincreateinvoices.notification.zugferd.error=Błąd podczas tworzenia e-faktury: {0}
|
admincreateinvoices.notification.zugferd.error=Błąd podczas tworzenia e-faktury: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=Brak pozycji rozliczeniowych dla e-faktury
|
admincreateinvoices.notification.zugferd.nopositions=Brak pozycji rozliczeniowych dla e-faktury
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=Nie udało się utworzyć e-faktury {0}, żadne faktury nie zostały wysłane: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=Walidacja nie powiodła się dla: {0}. Żadne faktury nie zostały wysłane.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Błąd podczas tworzenia zbiorczego pliku ZIP: {0}
|
||||||
|
|||||||
@@ -1084,3 +1084,6 @@ admincreateinvoices.notification.zugferd.created=Электронный счёт
|
|||||||
admincreateinvoices.notification.zugferd.invalid=Электронный счёт создан, но проверка не пройдена. Подробности в отчёте о проверке в ZIP-файле.
|
admincreateinvoices.notification.zugferd.invalid=Электронный счёт создан, но проверка не пройдена. Подробности в отчёте о проверке в ZIP-файле.
|
||||||
admincreateinvoices.notification.zugferd.error=Ошибка при создании электронного счёта: {0}
|
admincreateinvoices.notification.zugferd.error=Ошибка при создании электронного счёта: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=Нет позиций для выставления электронного счёта
|
admincreateinvoices.notification.zugferd.nopositions=Нет позиций для выставления электронного счёта
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=Не удалось создать электронный счёт {0}, счета не были отправлены: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=Проверка не пройдена для: {0}. Счета не были отправлены.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Ошибка при создании общего ZIP-файла: {0}
|
||||||
|
|||||||
@@ -1084,3 +1084,6 @@ admincreateinvoices.notification.zugferd.created={0} numaralı e-fatura oluştur
|
|||||||
admincreateinvoices.notification.zugferd.invalid=E-fatura oluşturuldu ancak doğrulama başarısız oldu. Ayrıntılar ZIP dosyasındaki doğrulama raporunda.
|
admincreateinvoices.notification.zugferd.invalid=E-fatura oluşturuldu ancak doğrulama başarısız oldu. Ayrıntılar ZIP dosyasındaki doğrulama raporunda.
|
||||||
admincreateinvoices.notification.zugferd.error=E-fatura oluşturulurken hata: {0}
|
admincreateinvoices.notification.zugferd.error=E-fatura oluşturulurken hata: {0}
|
||||||
admincreateinvoices.notification.zugferd.nopositions=E-fatura için faturalandırılabilir pozisyon yok
|
admincreateinvoices.notification.zugferd.nopositions=E-fatura için faturalandırılabilir pozisyon yok
|
||||||
|
admincreateinvoices.notification.zugferd.batcherror=E-fatura {0} oluşturulamadı, hiçbir fatura gönderilmedi: {1}
|
||||||
|
admincreateinvoices.notification.zugferd.invalidsend=Doğrulama başarısız oldu: {0}. Hiçbir fatura gönderilmedi.
|
||||||
|
admincreateinvoices.notification.zip.combined.error=Toplu ZIP dosyası oluşturulurken hata: {0}
|
||||||
|
|||||||
Reference in New Issue
Block a user