Compare commits
No commits in common. "058fb62849c63f00223e5dfcf7ed3ee357782e6b" and "449a6a77646ce380928d3cbd337f0b81f21d3d63" have entirely different histories.
058fb62849
...
449a6a7764
12
README.md
12
README.md
|
@ -29,18 +29,6 @@ val mailsWithEInvoices = mailReader.listAllMessagesWithEInvoice(MailAccount(
|
||||||
))
|
))
|
||||||
```
|
```
|
||||||
|
|
||||||
### Validate eInvoice
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
val validator = EInvoiceValidator()
|
|
||||||
val invoiceFile = File("ZUGFeRD.pdf") // or XRechnung,xml, ...
|
|
||||||
|
|
||||||
val result = validator.validate(invoiceFile)
|
|
||||||
|
|
||||||
println("Is valid? ${result.isValid}")
|
|
||||||
println(result.report)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Create eInvoice
|
## Create eInvoice
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
|
|
|
@ -20,7 +20,6 @@ val logbackVersion: String by project
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.mustangproject:library:$mustangVersion")
|
implementation("org.mustangproject:library:$mustangVersion")
|
||||||
implementation("org.mustangproject:validator:$mustangVersion")
|
|
||||||
|
|
||||||
implementation("org.eclipse.angus:angus-mail:$angusMailVersion")
|
implementation("org.eclipse.angus:angus-mail:$angusMailVersion")
|
||||||
|
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
package net.codinux.invoicing.validation
|
|
||||||
|
|
||||||
import org.mustangproject.validator.ZUGFeRDValidator
|
|
||||||
import java.io.File
|
|
||||||
import java.lang.reflect.Field
|
|
||||||
|
|
||||||
class EInvoiceValidator {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val SectionField = getPrivateField("section")
|
|
||||||
private val CriterionField = getPrivateField("criterion")
|
|
||||||
private val StacktraceField = getPrivateField("stacktrace")
|
|
||||||
|
|
||||||
private fun getPrivateField(fieldName: String): Field? = try {
|
|
||||||
org.mustangproject.validator.ValidationResultItem::class.java.getDeclaredField(fieldName).apply {
|
|
||||||
trySetAccessible()
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun validate(fileToValidate: File, disableNotices: Boolean = false): InvoiceValidationResult {
|
|
||||||
val validator = object : ZUGFeRDValidator() {
|
|
||||||
fun getContext() = this.context
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disableNotices) {
|
|
||||||
validator.disableNotices()
|
|
||||||
}
|
|
||||||
|
|
||||||
val report = validator.validate(fileToValidate.absolutePath)
|
|
||||||
|
|
||||||
val context = validator.getContext()
|
|
||||||
val isXmlValid = context.isValid
|
|
||||||
val xmlValidationResults = context.results.map { mapValidationResultItem(it) }
|
|
||||||
|
|
||||||
// TODO: currently it's not possible to get PDF validation result as for PDF validation the same context object
|
|
||||||
// is used and then in a private method before XML validation context.clear() gets called removing all PDF validation results
|
|
||||||
|
|
||||||
return InvoiceValidationResult(validator.wasCompletelyValid(), isXmlValid, xmlValidationResults, report)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun mapValidationResultItem(item: org.mustangproject.validator.ValidationResultItem) =
|
|
||||||
ValidationResultItem(mapSeverity(item), item.message, item.location, SectionField?.get(item) as? Int, CriterionField?.get(item) as? String, StacktraceField?.get(item) as? String)
|
|
||||||
|
|
||||||
private fun mapSeverity(item: org.mustangproject.validator.ValidationResultItem): ValidationResultSeverity {
|
|
||||||
var name = item.severity.name
|
|
||||||
name = name.first().uppercase() + name.substring(1)
|
|
||||||
|
|
||||||
return ValidationResultSeverity.valueOf(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package net.codinux.invoicing.validation
|
|
||||||
|
|
||||||
class InvoiceValidationResult(
|
|
||||||
/**
|
|
||||||
* If XML and, if supplied, PDF is valid.
|
|
||||||
*/
|
|
||||||
val isValid: Boolean,
|
|
||||||
/**
|
|
||||||
* If eInvoice XML is valid. If PDF is invalid, then [isValid] is false, but [isXmlValid] still can be true.
|
|
||||||
*/
|
|
||||||
val isXmlValid: Boolean,
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
val xmlValidationResults: List<ValidationResultItem>,
|
|
||||||
/**
|
|
||||||
* The validation report as a custom XML.
|
|
||||||
*/
|
|
||||||
val reportAsXml: String
|
|
||||||
) {
|
|
||||||
val countXmlNotices: Int by lazy { xmlValidationResults.count { it.severity == ValidationResultSeverity.Notice } }
|
|
||||||
|
|
||||||
val countXmlErrors: Int by lazy { xmlValidationResults.count { it.severity == ValidationResultSeverity.Error } }
|
|
||||||
|
|
||||||
val countXmlFatalOrExcepton: Int by lazy { xmlValidationResults.count { it.severity == ValidationResultSeverity.Fatal || it.severity == ValidationResultSeverity.Exception } }
|
|
||||||
|
|
||||||
override fun toString() = when (isValid) {
|
|
||||||
true -> "Valid: $reportAsXml"
|
|
||||||
false -> "Invalid: $reportAsXml"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package net.codinux.invoicing.validation
|
|
||||||
|
|
||||||
class ValidationResultItem(
|
|
||||||
val severity: ValidationResultSeverity,
|
|
||||||
val message: String,
|
|
||||||
val location: String?,
|
|
||||||
val section: Int?,
|
|
||||||
val criterion: String?,
|
|
||||||
val stacktrace: String? = null
|
|
||||||
) {
|
|
||||||
override fun toString() = "$severity: $message"
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package net.codinux.invoicing.validation
|
|
||||||
|
|
||||||
enum class ValidationResultSeverity {
|
|
||||||
Notice,
|
|
||||||
Warning,
|
|
||||||
Error,
|
|
||||||
Fatal,
|
|
||||||
Exception
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@ import net.codinux.invoicing.model.Invoice
|
||||||
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 net.codinux.invoicing.reader.EInvoiceReader
|
import net.codinux.invoicing.reader.EInvoiceReader
|
||||||
import net.codinux.invoicing.validation.EInvoiceValidator
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
@ -35,17 +34,6 @@ class Demonstration {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun validate() {
|
|
||||||
val validator = EInvoiceValidator()
|
|
||||||
val invoiceFile = File("ZUGFeRD.pdf") // or XRechnung,xml, ...
|
|
||||||
|
|
||||||
val result = validator.validate(invoiceFile)
|
|
||||||
|
|
||||||
println("Is valid? ${result.isValid}")
|
|
||||||
println(result.reportAsXml)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun create() {
|
fun create() {
|
||||||
val invoice = createInvoice()
|
val invoice = createInvoice()
|
||||||
val pdfResultFile = File.createTempFile("Zugferd", ".pdf")
|
val pdfResultFile = File.createTempFile("Zugferd", ".pdf")
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
package net.codinux.invoicing.validation
|
|
||||||
|
|
||||||
import assertk.assertThat
|
|
||||||
import assertk.assertions.*
|
|
||||||
import java.io.File
|
|
||||||
import kotlin.test.Test
|
|
||||||
|
|
||||||
class EInvoiceValidatorTest {
|
|
||||||
|
|
||||||
private val underTest = EInvoiceValidator()
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun validateXRechnung() {
|
|
||||||
val testFile = getTestFile("XRechnung.xml")
|
|
||||||
|
|
||||||
val result = underTest.validate(testFile)
|
|
||||||
|
|
||||||
assertThat(result.isValid).isFalse() // TODO: add required properties to XRechnung.xml
|
|
||||||
assertThat(result.reportAsXml).isNotEmpty()
|
|
||||||
assertThat(result.xmlValidationResults).hasSize(3)
|
|
||||||
assertThat(result.countXmlNotices).isEqualTo(0)
|
|
||||||
assertThat(result.countXmlErrors).isEqualTo(3)
|
|
||||||
assertThat(result.countXmlFatalOrExcepton).isEqualTo(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun validateZugferdPdf() {
|
|
||||||
val testFile = getTestFile("ZUGFeRD.pdf")
|
|
||||||
|
|
||||||
val result = underTest.validate(testFile)
|
|
||||||
|
|
||||||
|
|
||||||
assertThat(result.isValid).isTrue()
|
|
||||||
assertThat(result.reportAsXml).isNotEmpty()
|
|
||||||
assertThat(result.xmlValidationResults).hasSize(5)
|
|
||||||
assertThat(result.countXmlNotices).isEqualTo(5)
|
|
||||||
assertThat(result.countXmlErrors).isEqualTo(0)
|
|
||||||
assertThat(result.countXmlFatalOrExcepton).isEqualTo(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun validateZugferdXml() {
|
|
||||||
val testFile = getTestFile("ZUGFeRD.xml")
|
|
||||||
|
|
||||||
val result = underTest.validate(testFile)
|
|
||||||
|
|
||||||
assertThat(result.isValid).isTrue()
|
|
||||||
assertThat(result.reportAsXml).isNotEmpty()
|
|
||||||
assertThat(result.xmlValidationResults).hasSize(5)
|
|
||||||
assertThat(result.countXmlNotices).isEqualTo(5)
|
|
||||||
assertThat(result.countXmlErrors).isEqualTo(0)
|
|
||||||
assertThat(result.countXmlFatalOrExcepton).isEqualTo(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun getTestFile(filename: String): File =
|
|
||||||
File(this.javaClass.classLoader.getResource("files/$filename")!!.toURI())
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue