diff --git a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/CodeGenerator.kt b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/CodeGenerator.kt index a048f11..24c0099 100644 --- a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/CodeGenerator.kt +++ b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/CodeGenerator.kt @@ -4,6 +4,7 @@ import net.codinux.invoicing.model.codes.InvoiceTypeUseFor import net.codinux.invoicing.parser.genericode.CodeList import net.codinux.invoicing.parser.model.CodeListType import net.codinux.invoicing.parser.model.Column +import net.codinux.invoicing.parser.model.Row import java.io.File import java.util.Currency @@ -15,9 +16,9 @@ class CodeGenerator { matchedCodeLists.forEach { (type, codeLists) -> val (columns, rows) = if (type == CodeListType.IsoCurrencyCodes) mergeCurrencyData(codeLists.first, codeLists.second!!) else { - // Factur-X has the better column names and often also a Description column reorder(map(filter( - if (codeLists.second != null) codeLists.second!!.columns to codeLists.second!!.rows + // Factur-X (= codeLists.second) has the better column names and often also a Description column + if (codeLists.second != null) codeLists.second!!.columns to codeLists.second!!.rows else codeLists.first.columns to codeLists.first.rows ))) } @@ -29,7 +30,7 @@ class CodeGenerator { writer.appendLine("enum class ${type.className}(${columns.joinToString(", ") { "val ${getPropertyName(it)}: ${getDataType(it, columns, rows)}" } }) {") rows.forEach { row -> - writer.appendLine("\t${getEnumName(columns, row)}(${row.joinToString(", ") { getPropertyValue(it) } }),") + writer.appendLine("\t${getEnumName(columns, row.values)}(${row.values.joinToString(", ") { getPropertyValue(it) } }),") } writer.append("}") } @@ -42,7 +43,7 @@ class CodeGenerator { // ElectronicAddressScheme: ignore Source // Unit: ignore Source // PaymentMeansCodeFacturX: ignore Sens - private fun filter(columnsAndRows: Pair, List>>): Pair, List>> { + private fun filter(columnsAndRows: Pair, List>): Pair, List> { val (columns, rows) = columnsAndRows val columnToIgnore = columns.firstOrNull { it.name == "Source" || it.name == "Comment" || it.name == "Sens" || it.name == "French Name" } @@ -51,10 +52,10 @@ class CodeGenerator { } val indexToIgnore = columns.indexOf(columnToIgnore) - return columns.filterIndexed { index, _ -> index != indexToIgnore } to rows.map { it.filterIndexed { index, _ -> index != indexToIgnore } } + return columns.filterIndexed { index, _ -> index != indexToIgnore } to rows.onEach { it.removeValueAtIndex(indexToIgnore) } } - private fun map(columnsAndRows: Pair, List>>): Pair, List>> { + private fun map(columnsAndRows: Pair, List>): Pair, List> { val (columns, rows) = columnsAndRows val useForColumn = columns.firstOrNull { it.name == "EN16931 interpretation" } @@ -64,10 +65,10 @@ class CodeGenerator { removeAt(index) add(Column(columns.last().index + 1, "UseFor", "InvoiceTypeUseFor", "UseFor")) } - val modifiedRows = rows.map { it.toMutableList().apply { - val useFor = removeAt(index)?.toString() - add(if (useFor == "Credit Note") InvoiceTypeUseFor.CreditNote else InvoiceTypeUseFor.Invoice) - }} + val modifiedRows = rows.onEach { + val useFor = it.removeValueAtIndex(index)?.toString() + it.addValue(if (useFor == "Credit Note") InvoiceTypeUseFor.CreditNote else InvoiceTypeUseFor.Invoice) + } return modifiedColumns to modifiedRows } @@ -79,7 +80,7 @@ class CodeGenerator { * For Countries move englishNames column to the end, so that alpha2Code and alpha3Code are the first and second column. * For SchemeIdentifier move the schemeId column, which in most cases is null, to the end, so that the code is the first column. */ - private fun reorder(columnsAndRows: Pair, List>>): Pair, List>> { + private fun reorder(columnsAndRows: Pair, List>): Pair, List> { val (columns, rows) = columnsAndRows val reorderFirstColumn = columns.first().name in listOf("English Name", "Scheme ID") @@ -89,10 +90,10 @@ class CodeGenerator { this.add(reorderedColumn) } - val reorderedRows = rows.map { it.toMutableList().apply { - val reorderedRow = this.removeAt(0) - this.add(reorderedRow) - }} + val reorderedRows = rows.onEach { + val reorderedRow = it.removeValueAtIndex(0) + it.addValue(reorderedRow) + } return reorderedColumns to reorderedRows } @@ -100,7 +101,7 @@ class CodeGenerator { return columnsAndRows } - private fun mergeCurrencyData(cefCodeList: CodeList, zugferdCodeList: net.codinux.invoicing.parser.excel.CodeList): Pair, List>> { + private fun mergeCurrencyData(cefCodeList: CodeList, zugferdCodeList: net.codinux.invoicing.parser.excel.CodeList): Pair, List> { val columns = listOf( Column(0, "alpha3Code", "String", "alpha3Code"), Column(1, "currencySymbol", "String", "currencySymbol"), @@ -108,13 +109,13 @@ class CodeGenerator { Column(3, "countries", "Set", "countries") ) - val cefByIsoCode = cefCodeList.rows.associateBy { it[0] } - val zugferdByIsoCode = zugferdCodeList.rows.groupBy { it[2] } + val cefByIsoCode = cefCodeList.rows.associateBy { it.values[0] } + val zugferdByIsoCode = zugferdCodeList.rows.groupBy { it.values[2] } val availableCurrencies = Currency.getAvailableCurrencies().associateBy { it.currencyCode } // TODO: there are 52 currencies in availableCurrencies that are not in CEF and Zugferd list val rows = cefByIsoCode.map { (isoCode, cefRow) -> val zugferdRows = zugferdByIsoCode[isoCode] ?: emptyList() - listOf(isoCode, availableCurrencies[isoCode]?.symbol, cefRow[1], zugferdRows.map { it[0] }.toSet()) + Row(listOf(isoCode, availableCurrencies[isoCode]?.symbol, cefRow.values[1], zugferdRows.map { it.values[0] }.toSet())) } return columns to rows @@ -151,9 +152,9 @@ class CodeGenerator { return "\"${value.toString().replace("\n", "").replace('"', '\'')}\"" } - private fun getDataType(column: Column, columns: List, rows: List>): String { + private fun getDataType(column: Column, columns: List, rows: List): String { val index = columns.indexOf(column) - val containsNullValues = rows.any { it[index] == null } + val containsNullValues = rows.any { it.values[index] == null } return when (column.dataType) { "string" -> "String" + (if (containsNullValues) "?" else "") diff --git a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/excel/CodeList.kt b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/excel/CodeList.kt index 8607fba..3024d35 100644 --- a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/excel/CodeList.kt +++ b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/excel/CodeList.kt @@ -2,6 +2,7 @@ package net.codinux.invoicing.parser.excel import net.codinux.invoicing.parser.model.CodeListType import net.codinux.invoicing.parser.model.Column +import net.codinux.invoicing.parser.model.Row data class CodeList( val type: CodeListType, @@ -10,7 +11,7 @@ data class CodeList( val usedInInvoiceFields: String?, val additionalUsedInInvoiceFields: String?, val columns: List, - val rows: List> + val rows: List ) { override fun toString() = "$name${usedInInvoiceFields?.let { ", $it" } ?: ""}" } \ No newline at end of file diff --git a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/excel/ZugferdExcelCodeListsParser.kt b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/excel/ZugferdExcelCodeListsParser.kt index d085618..52f8566 100644 --- a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/excel/ZugferdExcelCodeListsParser.kt +++ b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/excel/ZugferdExcelCodeListsParser.kt @@ -76,9 +76,10 @@ class ZugferdExcelCodeListsParser { // if this Code List has a description, ignore every second row, as in the second row is the description val rows = allRows.drop(5).filterIndexed { index, _ -> isTypeWithDescription == false || index % 2 == 0 }.map { row -> - columnIndices.map { getCellValue(row.getCell(it)) } + + val values = columnIndices.map { getCellValue(row.getCell(it)) } + ( if (isTypeWithDescription) listOf(getCellValue(allRows.get(row.rowNum + 1).getCell(descriptionColumnIndex))) else emptyList()) - }.filterNot { it.all { it == null } } // filter out empty rows + net.codinux.invoicing.parser.model.Row(values) + }.filterNot { it.values.all { it == null } } // filter out empty rows if (isTypeWithDescription) { columns.add(Column(indexOfNextEmptyCell!! - 1, "Description", "String", "Description")) diff --git a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/genericode/CefGenericodeCodelistsParser.kt b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/genericode/CefGenericodeCodelistsParser.kt index 5f4ae66..403bb12 100644 --- a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/genericode/CefGenericodeCodelistsParser.kt +++ b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/genericode/CefGenericodeCodelistsParser.kt @@ -4,6 +4,7 @@ import com.helger.genericode.Genericode10CodeListMarshaller import com.helger.xml.serialize.read.DOMReader import net.codinux.invoicing.parser.model.CodeListType import net.codinux.invoicing.parser.model.Column +import net.codinux.invoicing.parser.model.Row import net.codinux.log.logger import java.io.File import java.io.InputStream @@ -44,7 +45,7 @@ class CefGenericodeCodelistsParser { val columns = columnSet?.columnChoice.orEmpty().filterIsInstance().mapIndexed { index, col -> Column(index, col.id!!, col.data?.type!!, col.shortNameValue!!) } val rows = simpleCodeList?.row.orEmpty().map { row -> columns.map { column -> row.value.firstOrNull { (it.columnRef as? com.helger.genericode.v10.Column)?.id == column.id }?.simpleValueValue } } - return CodeList(getType(name), name, version, canonicalUri, canonicalVersionUri, columns, rows) + return CodeList(getType(name), name, version, canonicalUri, canonicalVersionUri, columns, rows.map { Row(it) }) } private fun getType(name: String): CodeListType = when (name) { diff --git a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/genericode/CodeList.kt b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/genericode/CodeList.kt index fa0d9e3..0d57d0d 100644 --- a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/genericode/CodeList.kt +++ b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/genericode/CodeList.kt @@ -2,6 +2,7 @@ package net.codinux.invoicing.parser.genericode import net.codinux.invoicing.parser.model.CodeListType import net.codinux.invoicing.parser.model.Column +import net.codinux.invoicing.parser.model.Row class CodeList( val type: CodeListType, @@ -10,7 +11,7 @@ class CodeList( val canonicalUri: String?, val canonicalVersionUri: String?, val columns: List, - val rows: List> + val rows: List ) { override fun toString() = "$name ${columns.joinToString { it.name }}, ${rows.size} rows" } \ No newline at end of file diff --git a/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/model/Row.kt b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/model/Row.kt new file mode 100644 index 0000000..4385aee --- /dev/null +++ b/e-invoice-spec-parser/src/main/kotlin/net/codinux/invoicing/parser/model/Row.kt @@ -0,0 +1,18 @@ +package net.codinux.invoicing.parser.model + +class Row( + values: List +) { + + val values: List = values.toMutableList() + + fun addValue(value: Any?) { + (values as? MutableList)?.add(value) + } + + fun removeValueAtIndex(index: Int): Any? = + (values as? MutableList)?.removeAt(index) + + + override fun toString() = values.joinToString() +} \ No newline at end of file