Using now Country and Currency enum to signal allowed values

This commit is contained in:
dankito 2024-12-04 23:07:41 +01:00
parent df9e554d3e
commit 806bdc6e4d
5 changed files with 39 additions and 13 deletions

View File

@ -2,6 +2,8 @@ package net.codinux.invoicing.mapper
import net.codinux.invoicing.calculator.AmountsCalculator import net.codinux.invoicing.calculator.AmountsCalculator
import net.codinux.invoicing.model.* 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.*
import org.mustangproject.BankDetails import org.mustangproject.BankDetails
import org.mustangproject.Invoice import org.mustangproject.Invoice
@ -17,9 +19,18 @@ open class MustangMapper(
protected open val calculator: AmountsCalculator = AmountsCalculator() 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 { open fun mapToTransaction(invoice: net.codinux.invoicing.model.Invoice): IExportableTransaction = Invoice().apply {
this.number = invoice.details.invoiceNumber this.number = invoice.details.invoiceNumber
this.issueDate = map(invoice.details.invoiceDate) this.issueDate = map(invoice.details.invoiceDate)
this.currency = invoice.details.currency.alpha3Code
this.sender = mapParty(invoice.supplier) this.sender = mapParty(invoice.supplier)
this.recipient = mapParty(invoice.customer) this.recipient = mapParty(invoice.customer)
@ -42,7 +53,7 @@ open class MustangMapper(
} }
open fun mapParty(party: Party): TradeParty = TradeParty( 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 { ).apply {
this.setAdditionalAddress(party.additionalAddressLine) this.setAdditionalAddress(party.additionalAddressLine)
@ -94,7 +105,8 @@ open class MustangMapper(
open fun mapToInvoice(invoice: Invoice) = net.codinux.invoicing.model.Invoice( 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), supplier = mapParty(invoice.sender),
customer = mapParty(invoice.recipient), customer = mapParty(invoice.recipient),
@ -108,7 +120,8 @@ open class MustangMapper(
) )
open fun mapParty(party: TradeParty) = Party( 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.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) } 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") @JvmName("mapNullable")
protected fun map(date: LocalDate?) = protected fun map(date: LocalDate?) =

View File

@ -1,11 +1,14 @@
package net.codinux.invoicing.model package net.codinux.invoicing.model
import net.codinux.invoicing.model.codes.Currency
import java.time.LocalDate import java.time.LocalDate
class InvoiceDetails( class InvoiceDetails(
val invoiceNumber: String, val invoiceNumber: String,
val invoiceDate: LocalDate, val invoiceDate: LocalDate,
val currency: Currency = Currency.EUR,
val dueDate: LocalDate? = null, val dueDate: LocalDate? = null,
val paymentDescription: String? = null, val paymentDescription: String? = null,
) { ) {

View File

@ -1,5 +1,7 @@
package net.codinux.invoicing.model package net.codinux.invoicing.model
import net.codinux.invoicing.model.codes.Country
class Party( class Party(
val name: String, val name: String,
@ -10,10 +12,7 @@ class Party(
val additionalAddressLine: String? = null, val additionalAddressLine: String? = null,
var postalCode: String?, var postalCode: String?,
val city: String, val city: String,
/** val country: Country = Country.DE,
* 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 vatId: String? = null, val vatId: String? = null,

View File

@ -2,6 +2,8 @@ package net.codinux.invoicing.test
import net.codinux.invoicing.calculator.AmountsCalculator import net.codinux.invoicing.calculator.AmountsCalculator
import net.codinux.invoicing.model.* 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.math.BigDecimal
import java.time.LocalDate import java.time.LocalDate
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@ -17,7 +19,7 @@ object DataGenerator {
val SupplierAdditionalAddressLine: String? = null val SupplierAdditionalAddressLine: String? = null
const val SupplierPostalCode = "12345" const val SupplierPostalCode = "12345"
const val SupplierCity = "Glückstadt" const val SupplierCity = "Glückstadt"
const val SupplierCountry = "DE" val SupplierCountry = Country.DE
const val SupplierVatId = "DE123456789" const val SupplierVatId = "DE123456789"
const val SupplierEmail = "working-class-hero@rock.me" const val SupplierEmail = "working-class-hero@rock.me"
const val SupplierPhone = "+4917012345678" const val SupplierPhone = "+4917012345678"
@ -29,7 +31,7 @@ object DataGenerator {
val CustomerAdditionalAddressLine: String? = null val CustomerAdditionalAddressLine: String? = null
const val CustomerPostalCode = SupplierPostalCode const val CustomerPostalCode = SupplierPostalCode
const val CustomerCity = SupplierCity const val CustomerCity = SupplierCity
const val CustomerCountry = "DE" val CustomerCountry = SupplierCountry
const val CustomerVatId = "DE987654321" const val CustomerVatId = "DE987654321"
const val CustomerEmail = "exploiter@your.boss" const val CustomerEmail = "exploiter@your.boss"
const val CustomerPhone = "+491234567890" const val CustomerPhone = "+491234567890"
@ -53,9 +55,10 @@ object DataGenerator {
customer: Party = createParty(CustomerName, CustomerAddress, CustomerAdditionalAddressLine, CustomerPostalCode, CustomerCity, CustomerCountry, customer: Party = createParty(CustomerName, CustomerAddress, CustomerAdditionalAddressLine, CustomerPostalCode, CustomerCity, CustomerCountry,
CustomerVatId, CustomerEmail, CustomerPhone, CustomerFax, bankDetails = CustomerBankDetails), CustomerVatId, CustomerEmail, CustomerPhone, CustomerFax, bankDetails = CustomerBankDetails),
items: List<InvoiceItem> = listOf(createItem()), items: List<InvoiceItem> = listOf(createItem()),
currency: Currency = Currency.EUR,
dueDate: LocalDate? = DueDate, dueDate: LocalDate? = DueDate,
paymentDescription: String? = dueDate?.let { "Zahlbar ohne Abzug bis ${DateTimeFormatter.ofPattern("dd.MM.yyyy").format(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) this.totals = AmountsCalculator().calculateTotalAmounts(this)
} }
@ -65,7 +68,7 @@ object DataGenerator {
additionalAddressLine: String? = SupplierAdditionalAddressLine, additionalAddressLine: String? = SupplierAdditionalAddressLine,
postalCode: String = SupplierPostalCode, postalCode: String = SupplierPostalCode,
city: String = SupplierCity, city: String = SupplierCity,
country: String? = SupplierCountry, country: Country = SupplierCountry,
vatId: String? = SupplierVatId, vatId: String? = SupplierVatId,
email: String? = SupplierEmail, email: String? = SupplierEmail,
phone: String? = SupplierPhone, phone: String? = SupplierPhone,

View File

@ -6,6 +6,7 @@ import net.codinux.invoicing.model.BankDetails
import net.codinux.invoicing.model.Invoice import net.codinux.invoicing.model.Invoice
import net.codinux.invoicing.model.InvoiceItem import net.codinux.invoicing.model.InvoiceItem
import net.codinux.invoicing.model.Party import net.codinux.invoicing.model.Party
import net.codinux.invoicing.model.codes.Country
import java.math.BigDecimal import java.math.BigDecimal
object InvoiceAsserter { object InvoiceAsserter {
@ -70,13 +71,13 @@ object InvoiceAsserter {
assertLineItem(invoice.items.first(), DataGenerator.ItemName, DataGenerator.ItemQuantity, DataGenerator.ItemUnit, DataGenerator.ItemUnitPrice, DataGenerator.ItemVatRate, DataGenerator.ItemDescription) 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.name).isEqualTo(name)
assertThat(party.address).isEqualTo(address) assertThat(party.address).isEqualTo(address)
assertThat(party.postalCode).isEqualTo(postalCode) assertThat(party.postalCode).isEqualTo(postalCode)
assertThat(party.city).isEqualTo(city) assertThat(party.city).isEqualTo(city)
assertThat(party.countryIsoCode).isEqualTo(country) assertThat(party.country).isEqualTo(country)
assertThat(party.vatId).isEqualTo(vatId) assertThat(party.vatId).isEqualTo(vatId)