Extracted class Row

This commit is contained in:
dankito 2024-12-12 12:35:41 +01:00
parent 1b6e753f3c
commit 18f819d86c
6 changed files with 49 additions and 26 deletions

View File

@ -4,6 +4,7 @@ import net.codinux.invoicing.model.codes.InvoiceTypeUseFor
import net.codinux.invoicing.parser.genericode.CodeList import net.codinux.invoicing.parser.genericode.CodeList
import net.codinux.invoicing.parser.model.CodeListType import net.codinux.invoicing.parser.model.CodeListType
import net.codinux.invoicing.parser.model.Column import net.codinux.invoicing.parser.model.Column
import net.codinux.invoicing.parser.model.Row
import java.io.File import java.io.File
import java.util.Currency import java.util.Currency
@ -15,9 +16,9 @@ class CodeGenerator {
matchedCodeLists.forEach { (type, codeLists) -> matchedCodeLists.forEach { (type, codeLists) ->
val (columns, rows) = if (type == CodeListType.IsoCurrencyCodes) mergeCurrencyData(codeLists.first, codeLists.second!!) else { 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( 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 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)}" } }) {") writer.appendLine("enum class ${type.className}(${columns.joinToString(", ") { "val ${getPropertyName(it)}: ${getDataType(it, columns, rows)}" } }) {")
rows.forEach { row -> 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("}") writer.append("}")
} }
@ -42,7 +43,7 @@ class CodeGenerator {
// ElectronicAddressScheme: ignore Source // ElectronicAddressScheme: ignore Source
// Unit: ignore Source // Unit: ignore Source
// PaymentMeansCodeFacturX: ignore Sens // PaymentMeansCodeFacturX: ignore Sens
private fun filter(columnsAndRows: Pair<List<Column>, List<List<Any?>>>): Pair<List<Column>, List<List<Any?>>> { private fun filter(columnsAndRows: Pair<List<Column>, List<Row>>): Pair<List<Column>, List<Row>> {
val (columns, rows) = columnsAndRows val (columns, rows) = columnsAndRows
val columnToIgnore = columns.firstOrNull { it.name == "Source" || it.name == "Comment" || it.name == "Sens" || it.name == "French Name" } 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) 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<Column>, List<List<Any?>>>): Pair<List<Column>, List<List<Any?>>> { private fun map(columnsAndRows: Pair<List<Column>, List<Row>>): Pair<List<Column>, List<Row>> {
val (columns, rows) = columnsAndRows val (columns, rows) = columnsAndRows
val useForColumn = columns.firstOrNull { it.name == "EN16931 interpretation" } val useForColumn = columns.firstOrNull { it.name == "EN16931 interpretation" }
@ -64,10 +65,10 @@ class CodeGenerator {
removeAt(index) removeAt(index)
add(Column(columns.last().index + 1, "UseFor", "InvoiceTypeUseFor", "UseFor")) add(Column(columns.last().index + 1, "UseFor", "InvoiceTypeUseFor", "UseFor"))
} }
val modifiedRows = rows.map { it.toMutableList().apply { val modifiedRows = rows.onEach {
val useFor = removeAt(index)?.toString() val useFor = it.removeValueAtIndex(index)?.toString()
add(if (useFor == "Credit Note") InvoiceTypeUseFor.CreditNote else InvoiceTypeUseFor.Invoice) it.addValue(if (useFor == "Credit Note") InvoiceTypeUseFor.CreditNote else InvoiceTypeUseFor.Invoice)
}} }
return modifiedColumns to modifiedRows 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 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. * 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<Column>, List<List<Any?>>>): Pair<List<Column>, List<List<Any?>>> { private fun reorder(columnsAndRows: Pair<List<Column>, List<Row>>): Pair<List<Column>, List<Row>> {
val (columns, rows) = columnsAndRows val (columns, rows) = columnsAndRows
val reorderFirstColumn = columns.first().name in listOf("English Name", "Scheme ID") val reorderFirstColumn = columns.first().name in listOf("English Name", "Scheme ID")
@ -89,10 +90,10 @@ class CodeGenerator {
this.add(reorderedColumn) this.add(reorderedColumn)
} }
val reorderedRows = rows.map { it.toMutableList().apply { val reorderedRows = rows.onEach {
val reorderedRow = this.removeAt(0) val reorderedRow = it.removeValueAtIndex(0)
this.add(reorderedRow) it.addValue(reorderedRow)
}} }
return reorderedColumns to reorderedRows return reorderedColumns to reorderedRows
} }
@ -100,7 +101,7 @@ class CodeGenerator {
return columnsAndRows return columnsAndRows
} }
private fun mergeCurrencyData(cefCodeList: CodeList, zugferdCodeList: net.codinux.invoicing.parser.excel.CodeList): Pair<List<Column>, List<List<Any?>>> { private fun mergeCurrencyData(cefCodeList: CodeList, zugferdCodeList: net.codinux.invoicing.parser.excel.CodeList): Pair<List<Column>, List<Row>> {
val columns = listOf( val columns = listOf(
Column(0, "alpha3Code", "String", "alpha3Code"), Column(0, "alpha3Code", "String", "alpha3Code"),
Column(1, "currencySymbol", "String", "currencySymbol"), Column(1, "currencySymbol", "String", "currencySymbol"),
@ -108,13 +109,13 @@ class CodeGenerator {
Column(3, "countries", "Set<String>", "countries") Column(3, "countries", "Set<String>", "countries")
) )
val cefByIsoCode = cefCodeList.rows.associateBy { it[0] } val cefByIsoCode = cefCodeList.rows.associateBy { it.values[0] }
val zugferdByIsoCode = zugferdCodeList.rows.groupBy { it[2] } 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 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 rows = cefByIsoCode.map { (isoCode, cefRow) ->
val zugferdRows = zugferdByIsoCode[isoCode] ?: emptyList() 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 return columns to rows
@ -151,9 +152,9 @@ class CodeGenerator {
return "\"${value.toString().replace("\n", "").replace('"', '\'')}\"" return "\"${value.toString().replace("\n", "").replace('"', '\'')}\""
} }
private fun getDataType(column: Column, columns: List<Column>, rows: List<List<Any?>>): String { private fun getDataType(column: Column, columns: List<Column>, rows: List<Row>): String {
val index = columns.indexOf(column) val index = columns.indexOf(column)
val containsNullValues = rows.any { it[index] == null } val containsNullValues = rows.any { it.values[index] == null }
return when (column.dataType) { return when (column.dataType) {
"string" -> "String" + (if (containsNullValues) "?" else "") "string" -> "String" + (if (containsNullValues) "?" else "")

View File

@ -2,6 +2,7 @@ package net.codinux.invoicing.parser.excel
import net.codinux.invoicing.parser.model.CodeListType import net.codinux.invoicing.parser.model.CodeListType
import net.codinux.invoicing.parser.model.Column import net.codinux.invoicing.parser.model.Column
import net.codinux.invoicing.parser.model.Row
data class CodeList( data class CodeList(
val type: CodeListType, val type: CodeListType,
@ -10,7 +11,7 @@ data class CodeList(
val usedInInvoiceFields: String?, val usedInInvoiceFields: String?,
val additionalUsedInInvoiceFields: String?, val additionalUsedInInvoiceFields: String?,
val columns: List<Column>, val columns: List<Column>,
val rows: List<List<Any?>> val rows: List<Row>
) { ) {
override fun toString() = "$name${usedInInvoiceFields?.let { ", $it" } ?: ""}" override fun toString() = "$name${usedInInvoiceFields?.let { ", $it" } ?: ""}"
} }

View File

@ -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 // 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 -> 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()) ( 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) { if (isTypeWithDescription) {
columns.add(Column(indexOfNextEmptyCell!! - 1, "Description", "String", "Description")) columns.add(Column(indexOfNextEmptyCell!! - 1, "Description", "String", "Description"))

View File

@ -4,6 +4,7 @@ import com.helger.genericode.Genericode10CodeListMarshaller
import com.helger.xml.serialize.read.DOMReader import com.helger.xml.serialize.read.DOMReader
import net.codinux.invoicing.parser.model.CodeListType import net.codinux.invoicing.parser.model.CodeListType
import net.codinux.invoicing.parser.model.Column import net.codinux.invoicing.parser.model.Column
import net.codinux.invoicing.parser.model.Row
import net.codinux.log.logger import net.codinux.log.logger
import java.io.File import java.io.File
import java.io.InputStream import java.io.InputStream
@ -44,7 +45,7 @@ class CefGenericodeCodelistsParser {
val columns = columnSet?.columnChoice.orEmpty().filterIsInstance<com.helger.genericode.v10.Column>().mapIndexed { index, col -> Column(index, col.id!!, col.data?.type!!, col.shortNameValue!!) } val columns = columnSet?.columnChoice.orEmpty().filterIsInstance<com.helger.genericode.v10.Column>().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 } } 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) { private fun getType(name: String): CodeListType = when (name) {

View File

@ -2,6 +2,7 @@ package net.codinux.invoicing.parser.genericode
import net.codinux.invoicing.parser.model.CodeListType import net.codinux.invoicing.parser.model.CodeListType
import net.codinux.invoicing.parser.model.Column import net.codinux.invoicing.parser.model.Column
import net.codinux.invoicing.parser.model.Row
class CodeList( class CodeList(
val type: CodeListType, val type: CodeListType,
@ -10,7 +11,7 @@ class CodeList(
val canonicalUri: String?, val canonicalUri: String?,
val canonicalVersionUri: String?, val canonicalVersionUri: String?,
val columns: List<Column>, val columns: List<Column>,
val rows: List<List<String?>> val rows: List<Row>
) { ) {
override fun toString() = "$name ${columns.joinToString { it.name }}, ${rows.size} rows" override fun toString() = "$name ${columns.joinToString { it.name }}, ${rows.size} rows"
} }

View File

@ -0,0 +1,18 @@
package net.codinux.invoicing.parser.model
class Row(
values: List<Any?>
) {
val values: List<Any?> = values.toMutableList()
fun addValue(value: Any?) {
(values as? MutableList<Any?>)?.add(value)
}
fun removeValueAtIndex(index: Int): Any? =
(values as? MutableList<Any?>)?.removeAt(index)
override fun toString() = values.joinToString()
}