From 07007ad6191706db1fca7e0fd5aef777b11bf03f Mon Sep 17 00:00:00 2001 From: dankito Date: Wed, 20 Nov 2024 22:59:23 +0100 Subject: [PATCH] Implemented InvoicingResource to create eInvoices via REST API --- build.gradle.kts | 12 ++++++ .../invoicing/api/InvoicingResource.kt | 43 +++++++++++++++++++ .../invoicing/service/InvoicingService.kt | 30 +++++++++++++ .../src/main/resources/application.properties | 7 ++- .../invoicing/api/InvoicingResourceIT.kt | 6 +++ .../invoicing/api/InvoicingResourceTest.kt | 20 +++++++++ .../src/main/resources/META-INF/beans.xml | 0 7 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 e-invoice-api/src/main/kotlin/net/codinux/invoicing/api/InvoicingResource.kt create mode 100644 e-invoice-api/src/main/kotlin/net/codinux/invoicing/service/InvoicingService.kt create mode 100644 e-invoice-api/src/native-test/kotlin/net/codinux/invoicing/api/InvoicingResourceIT.kt create mode 100644 e-invoice-api/src/test/kotlin/net/codinux/invoicing/api/InvoicingResourceTest.kt create mode 100644 e-invoicing-domain/src/main/resources/META-INF/beans.xml diff --git a/build.gradle.kts b/build.gradle.kts index 94b4ed7..e663bf4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,15 @@ +buildscript { + val kotlinVersion: String by extra + + repositories { + mavenCentral() + } + dependencies { + // don't know why but otherwise Quarkus is not able to index the classes of e-invoice-domain + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + } +} + allprojects { group = "net.codinux.invoicing" diff --git a/e-invoice-api/src/main/kotlin/net/codinux/invoicing/api/InvoicingResource.kt b/e-invoice-api/src/main/kotlin/net/codinux/invoicing/api/InvoicingResource.kt new file mode 100644 index 0000000..eb311e6 --- /dev/null +++ b/e-invoice-api/src/main/kotlin/net/codinux/invoicing/api/InvoicingResource.kt @@ -0,0 +1,43 @@ +package net.codinux.invoicing.api + +import jakarta.ws.rs.* +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import net.codinux.invoicing.model.Invoice +import net.codinux.invoicing.service.InvoicingService +import org.eclipse.microprofile.openapi.annotations.Operation + +@Path("") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +class InvoicingResource( + private val service: InvoicingService +) { + + @Path("xrechnung") + @POST + @Produces(MediaType.APPLICATION_XML) + @Operation(summary = "Create a XRechnung XML") + fun createXRechnung(invoice: Invoice) = + service.createXRechnung(invoice) + + @Path("facturx/xml") + @POST + @Produces(MediaType.APPLICATION_XML) + @Operation(summary = "Create a Factur-X / ZUGFeRD XML (ZUGFeRD is a synonym for Factur-X)") + fun createFacturXXml(invoice: Invoice) = + service.createFacturXXml(invoice) + + @Path("facturx/pdf") + @POST + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Operation(summary = "Create a Factur-X / ZUGFeRD XML, transforms it to PDF and attaches before created XML to it") + fun createFacturXPdf(invoice: Invoice): Response { + val pdfFile = service.createFacturXPdf(invoice) + + return Response.ok(pdfFile) + .header("Content-Disposition", "attachment;filename=\"Invoice.pdf\"") + .build() + } + +} \ No newline at end of file diff --git a/e-invoice-api/src/main/kotlin/net/codinux/invoicing/service/InvoicingService.kt b/e-invoice-api/src/main/kotlin/net/codinux/invoicing/service/InvoicingService.kt new file mode 100644 index 0000000..7bc6340 --- /dev/null +++ b/e-invoice-api/src/main/kotlin/net/codinux/invoicing/service/InvoicingService.kt @@ -0,0 +1,30 @@ +package net.codinux.invoicing.service + +import jakarta.inject.Singleton +import net.codinux.invoicing.creation.EInvoiceCreator +import net.codinux.invoicing.model.Invoice +import java.io.File + +@Singleton +class InvoicingService { + + private val creator = EInvoiceCreator() + + + fun createXRechnung(invoice: Invoice): String = + creator.createXRechnungXml(invoice) + + fun createFacturXXml(invoice: Invoice): String = + creator.createZugferdXml(invoice) + + fun createFacturXPdf(invoice: Invoice): File { + val resultFile = File.createTempFile("factur-x", ".pdf").also { + it.deleteOnExit() + } + + creator.createZugferdPdf(invoice, resultFile) + + return resultFile + } + +} \ No newline at end of file diff --git a/e-invoice-api/src/main/resources/application.properties b/e-invoice-api/src/main/resources/application.properties index e6d25d7..fc78ca3 100644 --- a/e-invoice-api/src/main/resources/application.properties +++ b/e-invoice-api/src/main/resources/application.properties @@ -6,10 +6,10 @@ quarkus.http.enable-compression=true -quarkus.http.cors=true +%dev.quarkus.http.cors=true quarkus.http.cors.origins=* quarkus.http.cors.headers=accept, authorization, content-type, x-requested-with -quarkus.http.cors.methods=GET, OPTIONS +quarkus.http.cors.methods=GET, POST, PUT, DELETE, OPTIONS # log request response times @@ -40,6 +40,9 @@ quarkus.log.loki.field.kubernetes.include=true quarkus.log.loki.field.kubernetes.prefix=off quarkus.log.loki.field.kubernetes.field.containername.include=false +# to turn off verbose FOP messages +quarkus.log.category."org.apache.fop.apps".level=ERROR + # Live reload diff --git a/e-invoice-api/src/native-test/kotlin/net/codinux/invoicing/api/InvoicingResourceIT.kt b/e-invoice-api/src/native-test/kotlin/net/codinux/invoicing/api/InvoicingResourceIT.kt new file mode 100644 index 0000000..4119199 --- /dev/null +++ b/e-invoice-api/src/native-test/kotlin/net/codinux/invoicing/api/InvoicingResourceIT.kt @@ -0,0 +1,6 @@ +package net.codinux.invoicing.api + +import io.quarkus.test.junit.QuarkusIntegrationTest + +@QuarkusIntegrationTest +class InvoicingResourceIT : InvoicingResourceTest() diff --git a/e-invoice-api/src/test/kotlin/net/codinux/invoicing/api/InvoicingResourceTest.kt b/e-invoice-api/src/test/kotlin/net/codinux/invoicing/api/InvoicingResourceTest.kt new file mode 100644 index 0000000..fcd7150 --- /dev/null +++ b/e-invoice-api/src/test/kotlin/net/codinux/invoicing/api/InvoicingResourceTest.kt @@ -0,0 +1,20 @@ +package net.codinux.invoicing.api + +import io.quarkus.test.junit.QuarkusTest +import io.restassured.RestAssured.given +import org.hamcrest.CoreMatchers.`is` +import org.junit.jupiter.api.Test + +@QuarkusTest +class InvoicingResourceTest { + + @Test + fun testHelloEndpoint() { + given() + .`when`().get("/hello") + .then() + .statusCode(200) + .body(`is`("Hello from Quarkus REST")) + } + +} \ No newline at end of file diff --git a/e-invoicing-domain/src/main/resources/META-INF/beans.xml b/e-invoicing-domain/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..e69de29