From 806bdc6e4d7c2d7b7e4d11cc4e1c4a04ece0a324 Mon Sep 17 00:00:00 2001 From: dankito Date: Wed, 4 Dec 2024 23:07:41 +0100 Subject: [PATCH] Using now Country and Currency enum to signal allowed values --- .../codinux/invoicing/mapper/MustangMapper.kt | 26 ++++++++++++++++--- .../codinux/invoicing/model/InvoiceDetails.kt | 3 +++ .../net/codinux/invoicing/model/Party.kt | 7 +++-- .../codinux/invoicing/test/DataGenerator.kt | 11 +++++--- .../codinux/invoicing/test/InvoiceAsserter.kt | 5 ++-- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/mapper/MustangMapper.kt b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/mapper/MustangMapper.kt index 9cae491..a666714 100644 --- a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/mapper/MustangMapper.kt +++ b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/mapper/MustangMapper.kt @@ -2,6 +2,8 @@ package net.codinux.invoicing.mapper import net.codinux.invoicing.calculator.AmountsCalculator import net.codinux.invoicing.model.* +import net.codinux.invoicing.model.codes.Country +import net.codinux.invoicing.model.codes.Currency import org.mustangproject.* import org.mustangproject.BankDetails import org.mustangproject.Invoice @@ -17,9 +19,18 @@ open class MustangMapper( protected open val calculator: AmountsCalculator = AmountsCalculator() ) { + companion object { + val CountriesByIsoCode = Country.entries.associateBy { it.alpha2Code } + + val CurrenciesByIsoCode = Currency.entries.associateBy { it.alpha3Code } + } + + open fun mapToTransaction(invoice: net.codinux.invoicing.model.Invoice): IExportableTransaction = Invoice().apply { this.number = invoice.details.invoiceNumber this.issueDate = map(invoice.details.invoiceDate) + this.currency = invoice.details.currency.alpha3Code + this.sender = mapParty(invoice.supplier) this.recipient = mapParty(invoice.customer) @@ -42,7 +53,7 @@ open class MustangMapper( } open fun mapParty(party: Party): TradeParty = TradeParty( - party.name, party.address, party.postalCode, party.city, party.countryIsoCode + party.name, party.address, party.postalCode, party.city, party.country.alpha2Code ).apply { this.setAdditionalAddress(party.additionalAddressLine) @@ -94,7 +105,8 @@ open class MustangMapper( open fun mapToInvoice(invoice: Invoice) = net.codinux.invoicing.model.Invoice( - details = InvoiceDetails(invoice.number, map(invoice.issueDate), map(invoice.dueDate ?: invoice.paymentTerms?.dueDate), invoice.paymentTermDescription ?: invoice.paymentTerms?.description), + // TODO: what to do if currency code is unknown? Currently it throws an exception, but i don't like that mapping fails just due to an unknown currency code + details = InvoiceDetails(invoice.number, map(invoice.issueDate), mapCurrency(invoice.currency), map(invoice.dueDate ?: invoice.paymentTerms?.dueDate), invoice.paymentTermDescription ?: invoice.paymentTerms?.description), supplier = mapParty(invoice.sender), customer = mapParty(invoice.recipient), @@ -108,7 +120,8 @@ open class MustangMapper( ) open fun mapParty(party: TradeParty) = Party( - party.name, party.street, party.additionalAddress, party.zip, party.location, party.country, party.vatID, + // TODO: what to do if country code is unknown? Currently it throws an exception, but i don't like that mapping fails just due to an unknown country code + party.name, party.street, party.additionalAddress, party.zip, party.location, mapCountry(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) } ) @@ -135,6 +148,13 @@ open class MustangMapper( } + private fun mapCountry(isoAlpha2CountryCode: String?): Country = + CountriesByIsoCode[isoAlpha2CountryCode] + ?: throw IllegalArgumentException("Unknown ISO Alpha-2 country code '$isoAlpha2CountryCode', therefore cannot map ISO code to Country") + + private fun mapCurrency(isoCurrencyCode: String?): Currency = + CurrenciesByIsoCode[isoCurrencyCode] + ?: throw IllegalArgumentException("Unknown ISO currency code '$isoCurrencyCode', therefore cannot map ISO code to Currency") @JvmName("mapNullable") protected fun map(date: LocalDate?) = diff --git a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/InvoiceDetails.kt b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/InvoiceDetails.kt index 98dbfc3..3812198 100644 --- a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/InvoiceDetails.kt +++ b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/InvoiceDetails.kt @@ -1,11 +1,14 @@ package net.codinux.invoicing.model +import net.codinux.invoicing.model.codes.Currency import java.time.LocalDate class InvoiceDetails( val invoiceNumber: String, val invoiceDate: LocalDate, + val currency: Currency = Currency.EUR, + val dueDate: LocalDate? = null, val paymentDescription: String? = null, ) { diff --git a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/Party.kt b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/Party.kt index 5553dfb..17e79e3 100644 --- a/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/Party.kt +++ b/e-invoice-domain/src/main/kotlin/net/codinux/invoicing/model/Party.kt @@ -1,5 +1,7 @@ package net.codinux.invoicing.model +import net.codinux.invoicing.model.codes.Country + class Party( val name: String, @@ -10,10 +12,7 @@ class Party( val additionalAddressLine: String? = null, var postalCode: String?, val city: String, - /** - * Two letter country ISO code, e.g. "us" for USA, "fr" for France, ... - */ - val countryIsoCode: String? = null, // TODO: use the full country name here and map to ISO code in MustangMapper? + val country: Country = Country.DE, val vatId: String? = null, diff --git a/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/test/DataGenerator.kt b/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/test/DataGenerator.kt index d44a96f..3a1296d 100644 --- a/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/test/DataGenerator.kt +++ b/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/test/DataGenerator.kt @@ -2,6 +2,8 @@ package net.codinux.invoicing.test import net.codinux.invoicing.calculator.AmountsCalculator import net.codinux.invoicing.model.* +import net.codinux.invoicing.model.codes.Country +import net.codinux.invoicing.model.codes.Currency import java.math.BigDecimal import java.time.LocalDate import java.time.format.DateTimeFormatter @@ -17,7 +19,7 @@ object DataGenerator { val SupplierAdditionalAddressLine: String? = null const val SupplierPostalCode = "12345" const val SupplierCity = "Glückstadt" - const val SupplierCountry = "DE" + val SupplierCountry = Country.DE const val SupplierVatId = "DE123456789" const val SupplierEmail = "working-class-hero@rock.me" const val SupplierPhone = "+4917012345678" @@ -29,7 +31,7 @@ object DataGenerator { val CustomerAdditionalAddressLine: String? = null const val CustomerPostalCode = SupplierPostalCode const val CustomerCity = SupplierCity - const val CustomerCountry = "DE" + val CustomerCountry = SupplierCountry const val CustomerVatId = "DE987654321" const val CustomerEmail = "exploiter@your.boss" const val CustomerPhone = "+491234567890" @@ -53,9 +55,10 @@ object DataGenerator { customer: Party = createParty(CustomerName, CustomerAddress, CustomerAdditionalAddressLine, CustomerPostalCode, CustomerCity, CustomerCountry, CustomerVatId, CustomerEmail, CustomerPhone, CustomerFax, bankDetails = CustomerBankDetails), items: List = listOf(createItem()), + currency: Currency = Currency.EUR, dueDate: LocalDate? = DueDate, paymentDescription: String? = dueDate?.let { "Zahlbar ohne Abzug bis ${DateTimeFormatter.ofPattern("dd.MM.yyyy").format(dueDate)}" }, - ) = Invoice(InvoiceDetails(invoiceNumber, invoiceDate, dueDate, paymentDescription), supplier, customer, items).apply { + ) = Invoice(InvoiceDetails(invoiceNumber, invoiceDate, currency, dueDate, paymentDescription), supplier, customer, items).apply { this.totals = AmountsCalculator().calculateTotalAmounts(this) } @@ -65,7 +68,7 @@ object DataGenerator { additionalAddressLine: String? = SupplierAdditionalAddressLine, postalCode: String = SupplierPostalCode, city: String = SupplierCity, - country: String? = SupplierCountry, + country: Country = SupplierCountry, vatId: String? = SupplierVatId, email: String? = SupplierEmail, phone: String? = SupplierPhone, diff --git a/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/test/InvoiceAsserter.kt b/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/test/InvoiceAsserter.kt index 2c27e73..a5093e8 100644 --- a/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/test/InvoiceAsserter.kt +++ b/e-invoice-domain/src/test/kotlin/net/codinux/invoicing/test/InvoiceAsserter.kt @@ -6,6 +6,7 @@ import net.codinux.invoicing.model.BankDetails import net.codinux.invoicing.model.Invoice import net.codinux.invoicing.model.InvoiceItem import net.codinux.invoicing.model.Party +import net.codinux.invoicing.model.codes.Country import java.math.BigDecimal object InvoiceAsserter { @@ -70,13 +71,13 @@ object InvoiceAsserter { assertLineItem(invoice.items.first(), DataGenerator.ItemName, DataGenerator.ItemQuantity, DataGenerator.ItemUnit, DataGenerator.ItemUnitPrice, DataGenerator.ItemVatRate, DataGenerator.ItemDescription) } - private fun assertParty(party: Party, name: String, address: String, postalCode: String, city: String, country: String?, vatId: String, email: String, phone: String, bankDetails: BankDetails?) { + private fun assertParty(party: Party, name: String, address: String, postalCode: String, city: String, country: Country, vatId: String, email: String, phone: String, bankDetails: BankDetails?) { assertThat(party.name).isEqualTo(name) assertThat(party.address).isEqualTo(address) assertThat(party.postalCode).isEqualTo(postalCode) assertThat(party.city).isEqualTo(city) - assertThat(party.countryIsoCode).isEqualTo(country) + assertThat(party.country).isEqualTo(country) assertThat(party.vatId).isEqualTo(vatId)