From 6ec302e50f4662dc3a017a95c8a6120a4c23ca45 Mon Sep 17 00:00:00 2001 From: dankito Date: Tue, 26 Nov 2024 15:57:14 +0100 Subject: [PATCH] Implemented attaching XRechnung to Factur-X PDF --- README.md | 4 +- .../invoicing/creation/EInvoiceCreator.kt | 41 ++++++++++++++++--- .../invoicing/model/EInvoiceXmlFormat.kt | 10 +++++ .../net/codinux/invoicing/Demonstration.kt | 5 ++- .../invoicing/creation/EInvoiceCreatorTest.kt | 13 ++++++ 5 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/EInvoiceXmlFormat.kt diff --git a/README.md b/README.md index d633480..0176b25 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ val creator = EInvoiceCreator() creator.attachInvoiceXmlToPdf(invoice, existingPdf, output) // or if you already have the invoice XML: -val invoiceXml: String = "..." // e.g. creator.createZugferdXml(invoice) +val invoiceXml = creator.createXRechnungXml(invoice) // or creator.createZugferdXml(invoice), ... -creator.attachInvoiceXmlToPdf(invoiceXml, existingPdf, output) +creator.attachInvoiceXmlToPdf(invoiceXml, EInvoiceXmlFormat.XRechnung, existingPdf, output) ``` \ No newline at end of file diff --git a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/creation/EInvoiceCreator.kt b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/creation/EInvoiceCreator.kt index c6a7cc5..9acfb1d 100644 --- a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/creation/EInvoiceCreator.kt +++ b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/creation/EInvoiceCreator.kt @@ -1,6 +1,7 @@ package net.codinux.invoicing.creation import net.codinux.invoicing.mapper.MustangMapper +import net.codinux.invoicing.model.EInvoiceXmlFormat import net.codinux.invoicing.model.Invoice import org.mustangproject.ZUGFeRD.* import java.io.File @@ -36,14 +37,30 @@ open class EInvoiceCreator( open fun createFacturXPdf(invoice: Invoice, outputFile: File) { val xml = createFacturXXml(invoice) + + createFacturXPdf(xml, EInvoiceXmlFormat.FacturX, outputFile) + } + + /** + * Synonym for [createFacturXPdfWithXRechnungXML] (ZUGFeRD 2 is a synonym for Factur-X). + */ + open fun createZugferdPdfWithXRechnungXML(invoice: Invoice, outputFile: File) = createFacturXPdfWithXRechnungXML(invoice, outputFile) + + open fun createFacturXPdfWithXRechnungXML(invoice: Invoice, outputFile: File) { + val xml = createXRechnungXml(invoice) + + createFacturXPdf(xml, EInvoiceXmlFormat.XRechnung, outputFile) + } + + protected open fun createFacturXPdf(invoiceXml: String, format: EInvoiceXmlFormat, outputFile: File) { val xmlFile = File.createTempFile(outputFile.nameWithoutExtension, ".xml") - .also { it.writeText(xml) } + .also { it.writeText(invoiceXml) } val pdfFile = File(xmlFile.parentFile, xmlFile.nameWithoutExtension + ".pdf") val visualizer = ZUGFeRDVisualizer() visualizer.toPDF(xmlFile.absolutePath, pdfFile.absolutePath) - attachInvoiceXmlToPdf(xml, pdfFile, outputFile) + attachInvoiceXmlToPdf(invoiceXml, format, pdfFile, outputFile) xmlFile.delete() pdfFile.delete() @@ -51,13 +68,13 @@ open class EInvoiceCreator( open fun attachInvoiceXmlToPdf(invoice: Invoice, pdfFile: File, outputFile: File) = - attachInvoiceXmlToPdf(createFacturXXml(invoice), pdfFile, outputFile) + attachInvoiceXmlToPdf(createFacturXXml(invoice), EInvoiceXmlFormat.FacturX, pdfFile, outputFile) - open fun attachInvoiceXmlToPdf(invoiceXml: String, pdfFile: File, outputFile: File) { + open fun attachInvoiceXmlToPdf(invoiceXml: String, format: EInvoiceXmlFormat, pdfFile: File, outputFile: File) { val exporter = ZUGFeRDExporterFromA3() .setZUGFeRDVersion(2) - .setProfile("EN16931") // available values: MINIMUM, BASICWL, BASIC, CIUS, EN16931, EXTENDED, XRECHNUNG -// .disableFacturX() + .setProfile(getProfileNameForFormat(format)) + .disableFacturX() .setProducer("danki die geile Sau") .setCreator(System.getProperty("user.name")) @@ -78,4 +95,16 @@ open class EInvoiceCreator( return String(provider.xml, Charsets.UTF_8) } + + protected open fun getProfileNameForFormat(format: EInvoiceXmlFormat) = when (format) { + EInvoiceXmlFormat.FacturX -> "EN16931" // available values: MINIMUM, BASICWL, BASIC, CIUS, EN16931, EXTENDED, XRECHNUNG + EInvoiceXmlFormat.XRechnung -> "XRECHNUNG" + } + + protected open fun getFilenameForFormat(format: EInvoiceXmlFormat) = when (format) { + EInvoiceXmlFormat.FacturX -> "factur-x.xml" + EInvoiceXmlFormat.XRechnung -> "xrechnung.xml" + // other available values: "zugferd-invoice.xml" (ZF v2), "ZUGFeRD-invoice.xml" (ZF v1) ("order-x.xml", "cida.xml") + } + } \ No newline at end of file diff --git a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/EInvoiceXmlFormat.kt b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/EInvoiceXmlFormat.kt new file mode 100644 index 0000000..5c4dc87 --- /dev/null +++ b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/EInvoiceXmlFormat.kt @@ -0,0 +1,10 @@ +package net.codinux.invoicing.model + +enum class EInvoiceXmlFormat { + /** + * Factur-X is equal / synonym to ZUGFeRD 2 + */ + FacturX, + + XRechnung +} \ No newline at end of file diff --git a/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/Demonstration.kt b/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/Demonstration.kt index 51d6990..d6fdb66 100644 --- a/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/Demonstration.kt +++ b/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/Demonstration.kt @@ -3,6 +3,7 @@ package net.codinux.invoicing import net.codinux.invoicing.creation.EInvoiceCreator import net.codinux.invoicing.email.model.EmailAccount import net.codinux.invoicing.email.EmailsFetcher +import net.codinux.invoicing.model.EInvoiceXmlFormat import net.codinux.invoicing.model.Invoice import net.codinux.invoicing.model.InvoiceItem import net.codinux.invoicing.model.Party @@ -76,9 +77,9 @@ class Demonstration { creator.attachInvoiceXmlToPdf(invoice, existingPdf, output) // or if you already have the invoice XML: - val invoiceXml: String = "..." // e.g. creator.createZugferdXml(invoice) + val invoiceXml = creator.createXRechnungXml(invoice) // or creator.createZugferdXml(invoice), ... - creator.attachInvoiceXmlToPdf(invoiceXml, existingPdf, output) + creator.attachInvoiceXmlToPdf(invoiceXml, EInvoiceXmlFormat.XRechnung, existingPdf, output) } diff --git a/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/creation/EInvoiceCreatorTest.kt b/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/creation/EInvoiceCreatorTest.kt index b5f44ef..767db89 100644 --- a/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/creation/EInvoiceCreatorTest.kt +++ b/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/creation/EInvoiceCreatorTest.kt @@ -42,6 +42,19 @@ class EInvoiceCreatorTest { assertInvoiceXml(xml) } + @Test + fun createFacturXPdfWithXRechnungXML() { + val invoice = createInvoice() + val testFile = File.createTempFile("Zugferd", ".pdf") + + underTest.createFacturXPdfWithXRechnungXML(invoice, testFile) + + val importer = testFile.inputStream().use { ZUGFeRDInvoiceImporter(it) } + val xml = String(importer.rawXML, Charsets.UTF_8) + + assertInvoiceXml(xml) + } + private fun createInvoice() = DataGenerator.createInvoice()