Using now Country and Currency enum to signal allowed values
This commit is contained in:
parent
df9e554d3e
commit
806bdc6e4d
|
@ -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?) =
|
||||||
|
|
|
@ -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,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue