From 7ab88390f1ef290025981a4dd67afd237ccab08a Mon Sep 17 00:00:00 2001 From: dankito Date: Fri, 15 Nov 2024 00:42:47 +0100 Subject: [PATCH] Implemented EInvoiceReader --- .../codinux/invoicing/mapper/MustangMapper.kt | 31 ++++ .../invoicing/reader/EInvoiceReader.kt | 43 ++++++ .../invoicing/reader/EInvoiceReaderTest.kt | 89 +++++++++++ .../src/test/resources/files/XRechnung.xml | 140 ++++++++++++++++++ .../src/test/resources/files/ZUGFeRD.pdf | Bin 0 -> 32867 bytes .../src/test/resources/files/ZUGFeRD.xml | 134 +++++++++++++++++ 6 files changed, 437 insertions(+) create mode 100644 e-invoicing-domain/src/main/kotlin/net/codinux/invoicing/reader/EInvoiceReader.kt create mode 100644 e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/reader/EInvoiceReaderTest.kt create mode 100644 e-invoicing-domain/src/test/resources/files/XRechnung.xml create mode 100644 e-invoicing-domain/src/test/resources/files/ZUGFeRD.pdf create mode 100644 e-invoicing-domain/src/test/resources/files/ZUGFeRD.xml diff --git a/e-invoicing-domain/src/main/kotlin/net/codinux/invoicing/mapper/MustangMapper.kt b/e-invoicing-domain/src/main/kotlin/net/codinux/invoicing/mapper/MustangMapper.kt index 29670fc..8a85f2a 100644 --- a/e-invoicing-domain/src/main/kotlin/net/codinux/invoicing/mapper/MustangMapper.kt +++ b/e-invoicing-domain/src/main/kotlin/net/codinux/invoicing/mapper/MustangMapper.kt @@ -53,6 +53,30 @@ class MustangMapper { } + fun mapToInvoice(invoice: Invoice) = net.codinux.invoicing.model.Invoice( + invoiceNumber = invoice.number, + invoicingDate = map(invoice.issueDate), + sender = mapParty(invoice.sender), + recipient = mapParty(invoice.recipient), + items = invoice.zfItems.map { mapLineItem(it) }, + + dueDate = map(invoice.dueDate ?: invoice.paymentTerms?.dueDate), + paymentDescription = invoice.paymentTermDescription ?: invoice.paymentTerms?.description, + + buyerReference = invoice.referenceNumber + ) + + fun mapParty(party: TradeParty) = Party( + party.name, party.street, party.zip, party.location, party.country, party.vatID, + party.email ?: party.contact?.eMail, party.contact?.phone, party.contact?.fax, party.contact?.name, + party.bankDetails?.firstOrNull()?.let { net.codinux.invoicing.model.BankDetails(it.iban, it.bic, it.accountName) } + ) + + fun mapLineItem(item: IZUGFeRDExportableItem) = LineItem( + item.product.name, item.product.unit, item.quantity, item.price, item.product.vatPercent, item.product.description.takeUnless { it.isBlank() } + ) + + @JvmName("mapNullable") private fun map(date: LocalDate?) = date?.let { map(it) } @@ -63,4 +87,11 @@ class MustangMapper { private fun mapToInstant(date: LocalDate): Instant = date.atStartOfDay(ZoneId.systemDefault()).toInstant() + @JvmName("mapNullable") + private fun map(date: Date?) = + date?.let { map(it) } + + private fun map(date: Date): LocalDate = + date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() + } \ No newline at end of file diff --git a/e-invoicing-domain/src/main/kotlin/net/codinux/invoicing/reader/EInvoiceReader.kt b/e-invoicing-domain/src/main/kotlin/net/codinux/invoicing/reader/EInvoiceReader.kt new file mode 100644 index 0000000..498fecd --- /dev/null +++ b/e-invoicing-domain/src/main/kotlin/net/codinux/invoicing/reader/EInvoiceReader.kt @@ -0,0 +1,43 @@ +package net.codinux.invoicing.reader + +import net.codinux.invoicing.mapper.MustangMapper +import net.codinux.invoicing.model.Invoice +import org.mustangproject.ZUGFeRD.ZUGFeRDInvoiceImporter +import java.io.File +import java.io.InputStream + +class EInvoiceReader( + private val mapper: MustangMapper = MustangMapper() +) { + + fun readFromXml(file: File) = readFromXml(file.inputStream()) + + fun readFromXml(stream: InputStream): Invoice? { + val importer = ZUGFeRDInvoiceImporter() // XRechnungImporter only reads properties but not to a Invoice object + importer.fromXML(stream.reader().readText()) + + return extractInvoice(importer) + } + + fun extractFromPdf(file: File) = extractFromPdf(file.inputStream()) + + fun extractFromPdf(stream: InputStream): Invoice? { + val importer = ZUGFeRDInvoiceImporter(stream) + + return extractInvoice(importer) + } + + private fun extractInvoice(importer: ZUGFeRDInvoiceImporter): Invoice? { + val invoice = importer.extractInvoice() + + // TODO: the values LineTotalAmount, ChargeTotalAmount, AllowanceTotalAmount, TaxBasisTotalAmount, TaxTotalAmount, + // GrandTotalAmount, TotalPrepaidAmount adn DuePayableAmount are not extracted from XML document + // we could use TransactionCalculator to manually calculate these values - Importer also does this and asserts + // that its calculated value matches XML doc's GrandTotalAmount value. But then we would have to make some + // methods of TransactionCalculator public + // Another option would be to manually extract these values from XML document. + + return mapper.mapToInvoice(invoice) + } + +} \ No newline at end of file diff --git a/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/reader/EInvoiceReaderTest.kt b/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/reader/EInvoiceReaderTest.kt new file mode 100644 index 0000000..7d599d1 --- /dev/null +++ b/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/reader/EInvoiceReaderTest.kt @@ -0,0 +1,89 @@ +package net.codinux.invoicing.reader + +import assertk.assertThat +import assertk.assertions.hasSize +import assertk.assertions.isEqualTo +import assertk.assertions.isNotNull +import assertk.assertions.isNull +import net.codinux.invoicing.model.BankDetails +import net.codinux.invoicing.model.Invoice +import net.codinux.invoicing.model.LineItem +import net.codinux.invoicing.model.Party +import net.codinux.invoicing.test.DataGenerator +import java.io.InputStream +import java.math.BigDecimal +import kotlin.test.Test + +class EInvoiceReaderTest { + + private val underTest = EInvoiceReader() + + + @Test + fun readFromXml() { + val result = underTest.readFromXml(getTestFile("XRechnung.xml")) + + assertInvoice(result) + } + + @Test + fun extractFromPdf() { + val result = underTest.extractFromPdf(getTestFile("ZUGFeRD.pdf")) + + assertInvoice(result) + } + + + private fun getTestFile(filename: String): InputStream = + this.javaClass.classLoader.getResourceAsStream("files/$filename")!! + + private fun assertInvoice(invoice: Invoice?) { + assertThat(invoice).isNotNull() + + assertThat(invoice!!.invoiceNumber).isEqualTo(DataGenerator.InvoiceNumber) + assertThat(invoice.invoicingDate).isEqualTo(DataGenerator.InvoicingDate) + + assertParty(invoice.sender, DataGenerator.SenderName, DataGenerator.SenderStreet, DataGenerator.SenderPostalCode, DataGenerator.SenderCity, DataGenerator.SenderCountry, DataGenerator.SenderVatId, DataGenerator.SenderEmail, DataGenerator.SenderPhone, DataGenerator.SenderBankDetails) + + assertParty(invoice.recipient, DataGenerator.RecipientName, DataGenerator.RecipientStreet, DataGenerator.RecipientPostalCode, DataGenerator.RecipientCity, DataGenerator.RecipientCountry, DataGenerator.RecipientVatId, DataGenerator.RecipientEmail, DataGenerator.RecipientPhone, DataGenerator.RecipientBankDetails) + + assertThat(invoice.items).hasSize(1) + assertLineItem(invoice.items.first(), DataGenerator.ItemName, DataGenerator.ItemUnit, DataGenerator.ItemQuantity, DataGenerator.ItemPrice, DataGenerator.ItemVatPercentage, DataGenerator.ItemDescription) + } + + private fun assertParty(party: Party, name: String, street: String, postalCode: String, city: String, country: String?, vatId: String, email: String, phone: String, bankDetails: BankDetails?) { + assertThat(party.name).isEqualTo(name) + + assertThat(party.street).isEqualTo(street) + assertThat(party.postalCode).isEqualTo(postalCode) + assertThat(party.city).isEqualTo(city) + assertThat(party.countryIsoCode).isEqualTo(country) + + assertThat(party.vatId).isEqualTo(vatId) + + assertThat(party.email).isEqualTo(email) + assertThat(party.phone).isEqualTo(phone) + + if (bankDetails == null) { + assertThat(party.bankDetails).isNull() + } else { + assertThat(party.bankDetails!!.accountNumber).isEqualTo(bankDetails.accountNumber) + assertThat(party.bankDetails!!.bankCode).isEqualTo(bankDetails.bankCode) + // due to a bug in Mustang accountName doesn't get extracted from XML, see https://github.com/ZUGFeRD/mustangproject/issues/558 +// assertThat(party.bankDetails!!.accountHolderName).isEqualTo(bankDetails.accountHolderName) + } + } + + private fun assertLineItem(item: LineItem, name: String, unit: String, quantity: BigDecimal, price: BigDecimal, vatPercentage: BigDecimal, description: String?) { + assertThat(item.name).isEqualTo(name) + + assertThat(item.unit).isEqualTo(unit) + assertThat(item.quantity).isEqualTo(quantity.setScale(4)) + + assertThat(item.price).isEqualTo(price.setScale(4)) + assertThat(item.vatPercentage).isEqualTo(vatPercentage.setScale(2)) + +// assertThat(item.description).isEqualTo(description) + } + +} \ No newline at end of file diff --git a/e-invoicing-domain/src/test/resources/files/XRechnung.xml b/e-invoicing-domain/src/test/resources/files/XRechnung.xml new file mode 100644 index 0000000..2947203 --- /dev/null +++ b/e-invoicing-domain/src/test/resources/files/XRechnung.xml @@ -0,0 +1,140 @@ + + + + + + + + + urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 + + + + + urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 + + + + 12345 + 380 + + 20151021 + + + + + + 1 + + + Erbrachte Dienstleistungen + + + + 99.0000 + 1.0000 + + + + 1.0000 + + + + VAT + S + 19.00 + + + 99.00 + + + + + + Hochwürdiger Leistungserbringer + + + +4917012345678 + + + working-class-hero@rock.me + + + + 12345 + Fun Street 1 + Glückstadt + DE + + + working-class-hero@rock.me + + + DE123456789 + + + + Untertänigster Leistungsempfänger + + + +491234567890 + + + exploiter@your.boss + + + + 12345 + Party Street 1 + Glückstadt + DE + + + exploiter@your.boss + + + DE987654321 + + + + + + 12345 + EUR + + 58 + SEPA credit transfer + + DE00123456780987654321 + Manuela Musterfrau + + + ABZODEFFXXX + + + + 18.81 + VAT + 99.00 + S + 19.00 + + + Zahlbar ohne Abzug bis 15.06.2016 + + 20160615 + + + + 99.00 + 0.00 + 0.00 + 99.00 + 18.81 + 117.81 + 0.00 + 117.81 + + + + diff --git a/e-invoicing-domain/src/test/resources/files/ZUGFeRD.pdf b/e-invoicing-domain/src/test/resources/files/ZUGFeRD.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8a54b45e5db337e6dae801945d460fe97278574f GIT binary patch literal 32867 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 + + + + + + + urn:cen.eu:en16931:2017 + + + + 12345 + 380 + + 20151021 + + + + + + 1 + + + Erbrachte Dienstleistungen + + + + 99.0000 + 1.0000 + + + + 1.0000 + + + + VAT + S + 19.00 + + + 99.00 + + + + + + Hochwürdiger Leistungserbringer + + + +4917012345678 + + + working-class-hero@rock.me + + + + 12345 + Fun Street 1 + Glückstadt + DE + + + working-class-hero@rock.me + + + DE123456789 + + + + Untertänigster Leistungsempfänger + + + +491234567890 + + + exploiter@your.boss + + + + 12345 + Party Street 1 + Glückstadt + DE + + + exploiter@your.boss + + + DE987654321 + + + + + + 12345 + EUR + + 58 + SEPA credit transfer + + DE00123456780987654321 + Manuela Musterfrau + + + ABZODEFFXXX + + + + 18.81 + VAT + 99.00 + S + 19.00 + + + Zahlbar ohne Abzug bis 15.06.2016 + + 20160615 + + + + 99.00 + 0.00 + 0.00 + 99.00 + 18.81 + 117.81 + 0.00 + 117.81 + + + +