Implemented extractXmlFromPdf(); extracted invoice assertions to InvoiceAsserter
This commit is contained in:
parent
7ab88390f1
commit
658c02296a
|
@ -10,24 +10,35 @@ class EInvoiceReader(
|
||||||
private val mapper: MustangMapper = MustangMapper()
|
private val mapper: MustangMapper = MustangMapper()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun readFromXml(file: File) = readFromXml(file.inputStream())
|
fun readFromXml(xmlFile: File) = readFromXml(xmlFile.inputStream())
|
||||||
|
|
||||||
fun readFromXml(stream: InputStream): Invoice? {
|
fun readFromXml(stream: InputStream) = readFromXml(stream.reader().readText())
|
||||||
|
|
||||||
|
fun readFromXml(xml: String): Invoice {
|
||||||
val importer = ZUGFeRDInvoiceImporter() // XRechnungImporter only reads properties but not to a Invoice object
|
val importer = ZUGFeRDInvoiceImporter() // XRechnungImporter only reads properties but not to a Invoice object
|
||||||
importer.fromXML(stream.reader().readText())
|
importer.fromXML(xml)
|
||||||
|
|
||||||
return extractInvoice(importer)
|
return extractInvoice(importer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun extractFromPdf(file: File) = extractFromPdf(file.inputStream())
|
fun extractFromPdf(pdfFile: File) = extractFromPdf(pdfFile.inputStream())
|
||||||
|
|
||||||
fun extractFromPdf(stream: InputStream): Invoice? {
|
fun extractFromPdf(stream: InputStream): Invoice {
|
||||||
val importer = ZUGFeRDInvoiceImporter(stream)
|
val importer = ZUGFeRDInvoiceImporter(stream)
|
||||||
|
|
||||||
return extractInvoice(importer)
|
return extractInvoice(importer)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractInvoice(importer: ZUGFeRDInvoiceImporter): Invoice? {
|
fun extractXmlFromPdf(pdfFile: File) = extractXmlFromPdf(pdfFile.inputStream())
|
||||||
|
|
||||||
|
fun extractXmlFromPdf(stream: InputStream): String {
|
||||||
|
val importer = ZUGFeRDInvoiceImporter(stream)
|
||||||
|
|
||||||
|
return String(importer.rawXML, Charsets.UTF_8)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun extractInvoice(importer: ZUGFeRDInvoiceImporter): Invoice {
|
||||||
val invoice = importer.extractInvoice()
|
val invoice = importer.extractInvoice()
|
||||||
|
|
||||||
// TODO: the values LineTotalAmount, ChargeTotalAmount, AllowanceTotalAmount, TaxBasisTotalAmount, TaxTotalAmount,
|
// TODO: the values LineTotalAmount, ChargeTotalAmount, AllowanceTotalAmount, TaxBasisTotalAmount, TaxTotalAmount,
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
package net.codinux.invoicing.creation
|
package net.codinux.invoicing.creation
|
||||||
|
|
||||||
import assertk.assertThat
|
|
||||||
import assertk.assertions.isNotEmpty
|
|
||||||
import net.codinux.invoicing.test.DataGenerator
|
import net.codinux.invoicing.test.DataGenerator
|
||||||
import net.codinux.invoicing.test.XPathAsserter
|
import net.codinux.invoicing.test.InvoiceAsserter
|
||||||
import org.mustangproject.ZUGFeRD.ZUGFeRDInvoiceImporter
|
import org.mustangproject.ZUGFeRD.ZUGFeRDInvoiceImporter
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.math.BigDecimal
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
class EInvoiceCreatorTest {
|
class EInvoiceCreatorTest {
|
||||||
|
@ -49,47 +46,7 @@ class EInvoiceCreatorTest {
|
||||||
private fun createInvoice() = DataGenerator.createInvoice()
|
private fun createInvoice() = DataGenerator.createInvoice()
|
||||||
|
|
||||||
private fun assertInvoiceXml(xml: String) {
|
private fun assertInvoiceXml(xml: String) {
|
||||||
assertThat(xml).isNotEmpty()
|
InvoiceAsserter.assertInvoiceXml(xml)
|
||||||
|
|
||||||
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, DataGenerator.SenderPhone)
|
|
||||||
|
|
||||||
val receiverXPath = "//rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty"
|
|
||||||
assertParty(asserter, receiverXPath, DataGenerator.RecipientName, DataGenerator.RecipientStreet, DataGenerator.RecipientPostalCode, DataGenerator.RecipientCity, DataGenerator.RecipientVatId, DataGenerator.RecipientEmail, DataGenerator.RecipientPhone)
|
|
||||||
|
|
||||||
val lineItemXPath = "//rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem"
|
|
||||||
assertLineItem(asserter, lineItemXPath, DataGenerator.ItemName, DataGenerator.ItemUnit, DataGenerator.ItemQuantity, DataGenerator.ItemPrice, DataGenerator.ItemVatPercentage, DataGenerator.ItemDescription)
|
|
||||||
}
|
|
||||||
|
|
||||||
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: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)
|
|
||||||
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, itemXPath: String, name: String, unit: String, quantity: BigDecimal, price: BigDecimal, vatPercentage: BigDecimal, description: String?) {
|
|
||||||
asserter.xpathHasValue("$itemXPath/ram:SpecifiedTradeProduct/ram:Name", name)
|
|
||||||
|
|
||||||
asserter.xpathHasValue("$itemXPath/ram:SpecifiedLineTradeDelivery/ram:BilledQuantity/@unitCode", unit)
|
|
||||||
asserter.xpathHasValue("$itemXPath/ram:SpecifiedLineTradeDelivery/ram:BilledQuantity", quantity, 4)
|
|
||||||
|
|
||||||
asserter.xpathHasValue("$itemXPath/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeSettlementLineMonetarySummation/ram:LineTotalAmount", price, 2)
|
|
||||||
asserter.xpathHasValue("$itemXPath/ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent", vatPercentage, 2)
|
|
||||||
|
|
||||||
// asserter.xpathHasValue("$partyXPath/ram:URIUniversalCommunication/ram:URIID", description)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,17 +1,8 @@
|
||||||
package net.codinux.invoicing.reader
|
package net.codinux.invoicing.reader
|
||||||
|
|
||||||
import assertk.assertThat
|
|
||||||
import assertk.assertions.hasSize
|
|
||||||
import assertk.assertions.isEqualTo
|
|
||||||
import assertk.assertions.isNotNull
|
|
||||||
import assertk.assertions.isNull
|
|
||||||
import net.codinux.invoicing.model.BankDetails
|
|
||||||
import net.codinux.invoicing.model.Invoice
|
import net.codinux.invoicing.model.Invoice
|
||||||
import net.codinux.invoicing.model.LineItem
|
import net.codinux.invoicing.test.InvoiceAsserter
|
||||||
import net.codinux.invoicing.model.Party
|
|
||||||
import net.codinux.invoicing.test.DataGenerator
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.math.BigDecimal
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
class EInvoiceReaderTest {
|
class EInvoiceReaderTest {
|
||||||
|
@ -33,57 +24,19 @@ class EInvoiceReaderTest {
|
||||||
assertInvoice(result)
|
assertInvoice(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun extractXmlFromPdf() {
|
||||||
|
val result = underTest.extractXmlFromPdf(getTestFile("ZUGFeRD.pdf"))
|
||||||
|
|
||||||
|
InvoiceAsserter.assertInvoiceXml(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getTestFile(filename: String): InputStream =
|
private fun getTestFile(filename: String): InputStream =
|
||||||
this.javaClass.classLoader.getResourceAsStream("files/$filename")!!
|
this.javaClass.classLoader.getResourceAsStream("files/$filename")!!
|
||||||
|
|
||||||
private fun assertInvoice(invoice: Invoice?) {
|
private fun assertInvoice(invoice: Invoice?) {
|
||||||
assertThat(invoice).isNotNull()
|
InvoiceAsserter.assertInvoice(invoice)
|
||||||
|
|
||||||
assertThat(invoice!!.invoiceNumber).isEqualTo(DataGenerator.InvoiceNumber)
|
|
||||||
assertThat(invoice.invoicingDate).isEqualTo(DataGenerator.InvoicingDate)
|
|
||||||
|
|
||||||
assertParty(invoice.sender, DataGenerator.SenderName, DataGenerator.SenderStreet, DataGenerator.SenderPostalCode, DataGenerator.SenderCity, DataGenerator.SenderCountry, DataGenerator.SenderVatId, DataGenerator.SenderEmail, DataGenerator.SenderPhone, DataGenerator.SenderBankDetails)
|
|
||||||
|
|
||||||
assertParty(invoice.recipient, DataGenerator.RecipientName, DataGenerator.RecipientStreet, DataGenerator.RecipientPostalCode, DataGenerator.RecipientCity, DataGenerator.RecipientCountry, DataGenerator.RecipientVatId, DataGenerator.RecipientEmail, DataGenerator.RecipientPhone, DataGenerator.RecipientBankDetails)
|
|
||||||
|
|
||||||
assertThat(invoice.items).hasSize(1)
|
|
||||||
assertLineItem(invoice.items.first(), DataGenerator.ItemName, DataGenerator.ItemUnit, DataGenerator.ItemQuantity, DataGenerator.ItemPrice, DataGenerator.ItemVatPercentage, DataGenerator.ItemDescription)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun assertParty(party: Party, name: String, street: String, postalCode: String, city: String, country: String?, vatId: String, email: String, phone: String, bankDetails: BankDetails?) {
|
|
||||||
assertThat(party.name).isEqualTo(name)
|
|
||||||
|
|
||||||
assertThat(party.street).isEqualTo(street)
|
|
||||||
assertThat(party.postalCode).isEqualTo(postalCode)
|
|
||||||
assertThat(party.city).isEqualTo(city)
|
|
||||||
assertThat(party.countryIsoCode).isEqualTo(country)
|
|
||||||
|
|
||||||
assertThat(party.vatId).isEqualTo(vatId)
|
|
||||||
|
|
||||||
assertThat(party.email).isEqualTo(email)
|
|
||||||
assertThat(party.phone).isEqualTo(phone)
|
|
||||||
|
|
||||||
if (bankDetails == null) {
|
|
||||||
assertThat(party.bankDetails).isNull()
|
|
||||||
} else {
|
|
||||||
assertThat(party.bankDetails!!.accountNumber).isEqualTo(bankDetails.accountNumber)
|
|
||||||
assertThat(party.bankDetails!!.bankCode).isEqualTo(bankDetails.bankCode)
|
|
||||||
// due to a bug in Mustang accountName doesn't get extracted from XML, see https://github.com/ZUGFeRD/mustangproject/issues/558
|
|
||||||
// assertThat(party.bankDetails!!.accountHolderName).isEqualTo(bankDetails.accountHolderName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun assertLineItem(item: LineItem, name: String, unit: String, quantity: BigDecimal, price: BigDecimal, vatPercentage: BigDecimal, description: String?) {
|
|
||||||
assertThat(item.name).isEqualTo(name)
|
|
||||||
|
|
||||||
assertThat(item.unit).isEqualTo(unit)
|
|
||||||
assertThat(item.quantity).isEqualTo(quantity.setScale(4))
|
|
||||||
|
|
||||||
assertThat(item.price).isEqualTo(price.setScale(4))
|
|
||||||
assertThat(item.vatPercentage).isEqualTo(vatPercentage.setScale(2))
|
|
||||||
|
|
||||||
// assertThat(item.description).isEqualTo(description)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
package net.codinux.invoicing.test
|
||||||
|
|
||||||
|
import assertk.assertThat
|
||||||
|
import assertk.assertions.*
|
||||||
|
import net.codinux.invoicing.model.BankDetails
|
||||||
|
import net.codinux.invoicing.model.Invoice
|
||||||
|
import net.codinux.invoicing.model.LineItem
|
||||||
|
import net.codinux.invoicing.model.Party
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
object InvoiceAsserter {
|
||||||
|
|
||||||
|
fun assertInvoiceXml(xml: String) {
|
||||||
|
assertThat(xml).isNotEmpty()
|
||||||
|
|
||||||
|
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, DataGenerator.SenderPhone)
|
||||||
|
|
||||||
|
val receiverXPath = "//rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty"
|
||||||
|
assertParty(asserter, receiverXPath, DataGenerator.RecipientName, DataGenerator.RecipientStreet, DataGenerator.RecipientPostalCode, DataGenerator.RecipientCity, DataGenerator.RecipientVatId, DataGenerator.RecipientEmail, DataGenerator.RecipientPhone)
|
||||||
|
|
||||||
|
val lineItemXPath = "//rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem"
|
||||||
|
assertLineItem(asserter, lineItemXPath, DataGenerator.ItemName, DataGenerator.ItemUnit, DataGenerator.ItemQuantity, DataGenerator.ItemPrice, DataGenerator.ItemVatPercentage, DataGenerator.ItemDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
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: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)
|
||||||
|
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, itemXPath: String, name: String, unit: String, quantity: BigDecimal, price: BigDecimal, vatPercentage: BigDecimal, description: String?) {
|
||||||
|
asserter.xpathHasValue("$itemXPath/ram:SpecifiedTradeProduct/ram:Name", name)
|
||||||
|
|
||||||
|
asserter.xpathHasValue("$itemXPath/ram:SpecifiedLineTradeDelivery/ram:BilledQuantity/@unitCode", unit)
|
||||||
|
asserter.xpathHasValue("$itemXPath/ram:SpecifiedLineTradeDelivery/ram:BilledQuantity", quantity, 4)
|
||||||
|
|
||||||
|
asserter.xpathHasValue("$itemXPath/ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeSettlementLineMonetarySummation/ram:LineTotalAmount", price, 2)
|
||||||
|
asserter.xpathHasValue("$itemXPath/ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent", vatPercentage, 2)
|
||||||
|
|
||||||
|
// asserter.xpathHasValue("$partyXPath/ram:URIUniversalCommunication/ram:URIID", description)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun assertInvoice(invoice: Invoice?) {
|
||||||
|
assertThat(invoice).isNotNull()
|
||||||
|
|
||||||
|
assertThat(invoice!!.invoiceNumber).isEqualTo(DataGenerator.InvoiceNumber)
|
||||||
|
assertThat(invoice.invoicingDate).isEqualTo(DataGenerator.InvoicingDate)
|
||||||
|
|
||||||
|
assertParty(invoice.sender, DataGenerator.SenderName, DataGenerator.SenderStreet, DataGenerator.SenderPostalCode, DataGenerator.SenderCity, DataGenerator.SenderCountry, DataGenerator.SenderVatId, DataGenerator.SenderEmail, DataGenerator.SenderPhone, DataGenerator.SenderBankDetails)
|
||||||
|
|
||||||
|
assertParty(invoice.recipient, DataGenerator.RecipientName, DataGenerator.RecipientStreet, DataGenerator.RecipientPostalCode, DataGenerator.RecipientCity, DataGenerator.RecipientCountry, DataGenerator.RecipientVatId, DataGenerator.RecipientEmail, DataGenerator.RecipientPhone, DataGenerator.RecipientBankDetails)
|
||||||
|
|
||||||
|
assertThat(invoice.items).hasSize(1)
|
||||||
|
assertLineItem(invoice.items.first(), DataGenerator.ItemName, DataGenerator.ItemUnit, DataGenerator.ItemQuantity, DataGenerator.ItemPrice, DataGenerator.ItemVatPercentage, DataGenerator.ItemDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertParty(party: Party, name: String, street: String, postalCode: String, city: String, country: String?, vatId: String, email: String, phone: String, bankDetails: BankDetails?) {
|
||||||
|
assertThat(party.name).isEqualTo(name)
|
||||||
|
|
||||||
|
assertThat(party.street).isEqualTo(street)
|
||||||
|
assertThat(party.postalCode).isEqualTo(postalCode)
|
||||||
|
assertThat(party.city).isEqualTo(city)
|
||||||
|
assertThat(party.countryIsoCode).isEqualTo(country)
|
||||||
|
|
||||||
|
assertThat(party.vatId).isEqualTo(vatId)
|
||||||
|
|
||||||
|
assertThat(party.email).isEqualTo(email)
|
||||||
|
assertThat(party.phone).isEqualTo(phone)
|
||||||
|
|
||||||
|
if (bankDetails == null) {
|
||||||
|
assertThat(party.bankDetails).isNull()
|
||||||
|
} else {
|
||||||
|
assertThat(party.bankDetails!!.accountNumber).isEqualTo(bankDetails.accountNumber)
|
||||||
|
assertThat(party.bankDetails!!.bankCode).isEqualTo(bankDetails.bankCode)
|
||||||
|
// due to a bug in Mustang accountName doesn't get extracted from XML, see https://github.com/ZUGFeRD/mustangproject/issues/558
|
||||||
|
// assertThat(party.bankDetails!!.accountHolderName).isEqualTo(bankDetails.accountHolderName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertLineItem(item: LineItem, name: String, unit: String, quantity: BigDecimal, price: BigDecimal, vatPercentage: BigDecimal, description: String?) {
|
||||||
|
assertThat(item.name).isEqualTo(name)
|
||||||
|
|
||||||
|
assertThat(item.unit).isEqualTo(unit)
|
||||||
|
assertThat(item.quantity).isEqualTo(quantity.setScale(4))
|
||||||
|
|
||||||
|
assertThat(item.price).isEqualTo(price.setScale(4))
|
||||||
|
assertThat(item.vatPercentage).isEqualTo(vatPercentage.setScale(2))
|
||||||
|
|
||||||
|
// assertThat(item.description).isEqualTo(description)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue