Added Party phone, fax and contact name; renamed taxNumber to vatId; made clear that it's the two letter ISO code for country, not the full country name

This commit is contained in:
dankito 2024-11-14 18:48:27 +01:00
parent 5aae0bfe77
commit c480b2ec5e
4 changed files with 31 additions and 16 deletions

View File

@ -2,6 +2,7 @@ package net.codinux.invoicing.mapper
import net.codinux.invoicing.model.LineItem import net.codinux.invoicing.model.LineItem
import net.codinux.invoicing.model.Party import net.codinux.invoicing.model.Party
import org.mustangproject.Contact
import org.mustangproject.Invoice import org.mustangproject.Invoice
import org.mustangproject.Item import org.mustangproject.Item
import org.mustangproject.Product import org.mustangproject.Product
@ -27,14 +28,16 @@ class MustangMapper {
} }
fun mapParty(party: Party): TradeParty = TradeParty( fun mapParty(party: Party): TradeParty = TradeParty(
party.name, party.street, party.postalCode, party.city, party.country party.name, party.street, party.postalCode, party.city, party.countryIsoCode
).apply { ).apply {
this.taxID = party.taxNumber this.taxID = party.vatId
// TODO: vatID?
// TODO: ID? // TODO: ID?
// TODO: description? // TODO: description?
this.email = party.email this.email = party.email
this.setContact(Contact(party.contactName, party.phone, party.email).apply {
this.fax = party.fax
})
} }
fun mapLineItem(item: LineItem): IZUGFeRDExportableItem = Item( fun mapLineItem(item: LineItem): IZUGFeRDExportableItem = Item(

View File

@ -9,13 +9,18 @@ class Party(
val street: String, val street: String,
var postalCode: String?, var postalCode: String?,
val city: String, val city: String,
val country: String? = null, /**
* 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 taxNumber: String? = null, // better name like vatTaxNumber? val vatId: String? = null,
// actually there can be multiple contacts in eInvoice data model, all containing an email, phone, fax and contact name
val email: String? = null, val email: String? = null,
// var telephoneNumber: String? = null, // simply telephone? var phone: String? = null,
// var website: String? = null, var fax: String? = null,
var contactName: String? = null,
) { ) {
override fun toString() = "$name, $city" override fun toString() = "$name, $city"
} }

View File

@ -42,16 +42,16 @@ class EInvoiceCreatorTest {
asserter.xpathHasValue("//rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString", DataGenerator.InvoicingDate.toString().replace("-", "")) asserter.xpathHasValue("//rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString", DataGenerator.InvoicingDate.toString().replace("-", ""))
val senderXPath = "//rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty" val senderXPath = "//rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty"
assertParty(asserter, senderXPath, DataGenerator.SenderName, DataGenerator.SenderStreet, DataGenerator.SenderPostalCode, DataGenerator.SenderCity, DataGenerator.SenderVatId, DataGenerator.SenderEmail) assertParty(asserter, senderXPath, DataGenerator.SenderName, DataGenerator.SenderStreet, DataGenerator.SenderPostalCode, DataGenerator.SenderCity, DataGenerator.SenderVatId, DataGenerator.SenderEmail, DataGenerator.SenderPhone)
val receiverXPath = "//rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty" val receiverXPath = "//rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty"
assertParty(asserter, receiverXPath, DataGenerator.RecipientName, DataGenerator.RecipientStreet, DataGenerator.RecipientPostalCode, DataGenerator.RecipientCity, DataGenerator.RecipientVatId, DataGenerator.RecipientEmail) assertParty(asserter, receiverXPath, DataGenerator.RecipientName, DataGenerator.RecipientStreet, DataGenerator.RecipientPostalCode, DataGenerator.RecipientCity, DataGenerator.RecipientVatId, DataGenerator.RecipientEmail, DataGenerator.RecipientPhone)
val lineItemXPath = "//rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem" val lineItemXPath = "//rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem"
assertLineItem(asserter, lineItemXPath, DataGenerator.ItemName, DataGenerator.ItemUnit, DataGenerator.ItemQuantity, DataGenerator.ItemPrice, DataGenerator.ItemVat, DataGenerator.ItemDescription) assertLineItem(asserter, lineItemXPath, DataGenerator.ItemName, DataGenerator.ItemUnit, DataGenerator.ItemQuantity, DataGenerator.ItemPrice, DataGenerator.ItemVat, DataGenerator.ItemDescription)
} }
private fun assertParty(asserter: XPathAsserter, partyXPath: String, name: String, street: String, postalCode: String, city: String, vatId: String, email: String) { private fun assertParty(asserter: XPathAsserter, partyXPath: String, name: String, street: String, postalCode: String, city: String, vatId: String, email: String, phone: String) {
asserter.xpathHasValue("$partyXPath/ram:Name", name) asserter.xpathHasValue("$partyXPath/ram:Name", name)
asserter.xpathHasValue("$partyXPath/ram:PostalTradeAddress/ram:LineOne", street) asserter.xpathHasValue("$partyXPath/ram:PostalTradeAddress/ram:LineOne", street)
@ -61,6 +61,8 @@ class EInvoiceCreatorTest {
asserter.xpathHasValue("$partyXPath/ram:SpecifiedTaxRegistration/ram:ID", vatId) asserter.xpathHasValue("$partyXPath/ram:SpecifiedTaxRegistration/ram:ID", vatId)
asserter.xpathHasValue("$partyXPath/ram:URIUniversalCommunication/ram:URIID", email) asserter.xpathHasValue("$partyXPath/ram:URIUniversalCommunication/ram:URIID", email)
asserter.xpathHasValue("$partyXPath/ram:DefinedTradeContact/ram:EmailURIUniversalCommunication/ram:URIID", email)
asserter.xpathHasValue("$partyXPath/ram:DefinedTradeContact/ram:TelephoneUniversalCommunication/ram:CompleteNumber", phone)
} }
private fun assertLineItem(asserter: XPathAsserter, partyXPath: String, name: String, unit: String, quantity: BigDecimal, price: BigDecimal, vatPercentage: BigDecimal, description: String?) { private fun assertLineItem(asserter: XPathAsserter, partyXPath: String, name: String, unit: String, quantity: BigDecimal, price: BigDecimal, vatPercentage: BigDecimal, description: String?) {

View File

@ -15,17 +15,19 @@ object DataGenerator {
const val SenderStreet = "Fun Street 1" const val SenderStreet = "Fun Street 1"
const val SenderPostalCode = "12345" const val SenderPostalCode = "12345"
const val SenderCity = "Glückstadt" const val SenderCity = "Glückstadt"
val SenderCountry: String? = null const val SenderCountry = "DE"
const val SenderVatId = "DE12345678" const val SenderVatId = "DE12345678"
const val SenderEmail = "working-class-hero@rock.me" const val SenderEmail = "working-class-hero@rock.me"
const val SenderPhone = "+4917012345678"
const val RecipientName = "Untertänigster Leistungsempfänger" const val RecipientName = "Untertänigster Leistungsempfänger"
const val RecipientStreet = "Party Street 1" const val RecipientStreet = "Party Street 1"
const val RecipientPostalCode = SenderPostalCode const val RecipientPostalCode = SenderPostalCode
const val RecipientCity = SenderCity const val RecipientCity = SenderCity
val RecipientCountry: String? = SenderCountry const val RecipientCountry = "DE"
const val RecipientVatId = "DE87654321" const val RecipientVatId = "DE87654321"
const val RecipientEmail = "exploiter@your.boss" const val RecipientEmail = "exploiter@your.boss"
const val RecipientPhone = "+4912345678"
const val ItemName = "Erbrachte Dienstleistungen" const val ItemName = "Erbrachte Dienstleistungen"
const val ItemUnit = "HUR" // EN code for 'hour' const val ItemUnit = "HUR" // EN code for 'hour'
@ -38,8 +40,8 @@ object DataGenerator {
fun createInvoice( fun createInvoice(
invoiceNumber: String = InvoiceNumber, invoiceNumber: String = InvoiceNumber,
invoicingDate: LocalDate = InvoicingDate, invoicingDate: LocalDate = InvoicingDate,
sender: Party = createParty(SenderName, SenderStreet, SenderPostalCode, SenderCity, SenderCountry, SenderVatId, SenderEmail), sender: Party = createParty(SenderName, SenderStreet, SenderPostalCode, SenderCity, SenderCountry, SenderVatId, SenderEmail, SenderPhone),
recipient: Party = createParty(RecipientName, RecipientStreet, RecipientPostalCode, RecipientCity, RecipientCountry, RecipientVatId, RecipientEmail), recipient: Party = createParty(RecipientName, RecipientStreet, RecipientPostalCode, RecipientCity, RecipientCountry, RecipientVatId, RecipientEmail, RecipientPhone),
items: List<LineItem> = listOf(createItem()), items: List<LineItem> = listOf(createItem()),
dueDate: LocalDate? = null dueDate: LocalDate? = null
) = Invoice(invoiceNumber, invoicingDate, sender, recipient, items, dueDate) ) = Invoice(invoiceNumber, invoicingDate, sender, recipient, items, dueDate)
@ -50,9 +52,12 @@ object DataGenerator {
postalCode: String = SenderPostalCode, postalCode: String = SenderPostalCode,
city: String = SenderCity, city: String = SenderCity,
country: String? = SenderCountry, country: String? = SenderCountry,
taxNumber: String? = SenderVatId, vatId: String? = SenderVatId,
email: String? = SenderEmail, email: String? = SenderEmail,
) = Party(name, streetName, postalCode, city, country, taxNumber, email) phone: String? = SenderPhone,
fax: String? = null,
contactName: String? = null
) = Party(name, streetName, postalCode, city, country, vatId, email, phone, fax, contactName)
fun createItem( fun createItem(
name: String = ItemName, name: String = ItemName,