diff --git a/e-invoicing-domain/build.gradle.kts b/e-invoicing-domain/build.gradle.kts
index 4b9ee34..02b0a1f 100644
--- a/e-invoicing-domain/build.gradle.kts
+++ b/e-invoicing-domain/build.gradle.kts
@@ -13,6 +13,7 @@ val mustangVersion: String by project
val klfVersion: String by project
val assertKVersion: String by project
+val xunitVersion: String by project
dependencies {
implementation("org.mustangproject:library:$mustangVersion")
@@ -23,6 +24,7 @@ dependencies {
testImplementation(kotlin("test"))
implementation("com.willowtreeapps.assertk:assertk:$assertKVersion")
+ testImplementation("org.xmlunit:xmlunit-core:$xunitVersion")
}
diff --git a/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/creation/EInvoiceCreatorTest.kt b/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/creation/EInvoiceCreatorTest.kt
index b1791d1..6edd27d 100644
--- a/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/creation/EInvoiceCreatorTest.kt
+++ b/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/creation/EInvoiceCreatorTest.kt
@@ -1,9 +1,10 @@
package net.codinux.invoicing.creation
import assertk.assertThat
-import assertk.assertions.contains
import assertk.assertions.isNotEmpty
import net.codinux.invoicing.test.DataGenerator
+import net.codinux.invoicing.test.XPathAsserter
+import java.math.BigDecimal
import kotlin.test.Test
class EInvoiceCreatorTest {
@@ -35,8 +36,43 @@ class EInvoiceCreatorTest {
private fun assertInvoiceXml(xml: String) {
assertThat(xml).isNotEmpty()
- assertThat(xml).contains("${DataGenerator.InvoiceNumber}")
- assertThat(xml).contains("""${DataGenerator.InvoicingDate.toString().replace("-", "")}""")
+ val asserter = XPathAsserter(xml)
+
+ asserter.xpathHasValue("//rsm:ExchangedDocument/ram:ID", DataGenerator.InvoiceNumber)
+ asserter.xpathHasValue("//rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString", DataGenerator.InvoicingDate.toString().replace("-", ""))
+
+ val senderXPath = "//rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty"
+ assertParty(asserter, senderXPath, DataGenerator.SenderName, DataGenerator.SenderStreet, DataGenerator.SenderPostalCode, DataGenerator.SenderCity, DataGenerator.SenderVatId, DataGenerator.SenderEmail)
+
+ val receiverXPath = "//rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty"
+ assertParty(asserter, receiverXPath, DataGenerator.RecipientName, DataGenerator.RecipientStreet, DataGenerator.RecipientPostalCode, DataGenerator.RecipientCity, DataGenerator.RecipientVatId, DataGenerator.RecipientEmail)
+
+ val lineItemXPath = "//rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem"
+ 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) {
+ asserter.xpathHasValue("$partyXPath/ram:Name", name)
+
+ asserter.xpathHasValue("$partyXPath/ram:PostalTradeAddress/ram:LineOne", street)
+ asserter.xpathHasValue("$partyXPath/ram:PostalTradeAddress/ram:PostcodeCode", postalCode)
+ asserter.xpathHasValue("$partyXPath/ram:PostalTradeAddress/ram:CityName", city)
+
+ asserter.xpathHasValue("$partyXPath/ram:SpecifiedTaxRegistration/ram:ID", vatId)
+
+ asserter.xpathHasValue("$partyXPath/ram:URIUniversalCommunication/ram:URIID", email)
+ }
+
+ private fun assertLineItem(asserter: XPathAsserter, partyXPath: String, name: String, unit: String, quantity: BigDecimal, price: BigDecimal, vatPercentage: BigDecimal, description: String?) {
+ asserter.xpathHasValue("$partyXPath/ram:SpecifiedTradeProduct/ram:Name", name)
+
+ asserter.xpathHasValue("$partyXPath/ram:SpecifiedLineTradeDelivery/ram:BilledQuantity/@unitCode", unit)
+ asserter.xpathHasValue("$partyXPath/ram:SpecifiedLineTradeDelivery/ram:BilledQuantity", quantity, 4)
+
+ asserter.xpathHasValue("$partyXPath/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeSettlementLineMonetarySummation/ram:LineTotalAmount", price, 2)
+ asserter.xpathHasValue("$partyXPath/ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent", vatPercentage, 2)
+
+// asserter.xpathHasValue("$partyXPath/ram:URIUniversalCommunication/ram:URIID", description)
}
}
\ No newline at end of file
diff --git a/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/test/XPathAsserter.kt b/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/test/XPathAsserter.kt
new file mode 100644
index 0000000..b60287f
--- /dev/null
+++ b/e-invoicing-domain/src/test/kotlin/net/codinux/invoicing/test/XPathAsserter.kt
@@ -0,0 +1,34 @@
+package net.codinux.invoicing.test
+
+import assertk.assertThat
+import assertk.assertions.isEqualTo
+import net.codinux.log.Platform
+import org.xmlunit.builder.Input
+import org.xmlunit.xpath.JAXPXPathEngine
+import java.math.BigDecimal
+import java.math.RoundingMode
+
+class XPathAsserter(
+ xml: String
+) {
+
+ private val source = Input.fromString(xml).build()
+
+ private val xpathEngine = JAXPXPathEngine().apply {
+ setNamespaceContext(mapOf(
+ "rsm" to "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100",
+ "ram" to "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100",
+ "udt" to "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
+ ))
+ }
+
+
+ fun xpathHasValue(xpath: String, value: String) {
+ assertThat(xpathEngine.evaluate(xpath, source)).isEqualTo(value)
+ }
+
+ fun xpathHasValue(xpath: String, value: BigDecimal, countDecimalPlatform: Int = 2) {
+ xpathHasValue(xpath, value.setScale(countDecimalPlatform, RoundingMode.HALF_UP).toString())
+ }
+
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 5099174..10e8f72 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -10,3 +10,4 @@ mustangVersion=2.14.2
klfVersion=1.6.2
assertKVersion=0.28.1
+xunitVersion=2.10.0
\ No newline at end of file