fix(dkv): fix Kennzeichen matching and NaN/invalid km values in Excel export
Three issues fixed:
1. Kennzeichen normalization: DKV PDF extracts plates without hyphens
("GP JL 740E" vs CSV-imported "GP-JL 740E"). Added _normalizeKennzeichen()
which strips hyphens, spaces, and dots before lookup — resolves vehicle
master match failure that caused Marke/Modell/Fahrer to appear empty.
2. Empty-string NaN: parser used ?? '0' which doesn't catch empty strings,
causing parseDE('') = NaN. Changed to || '0' for km, menge, and totals.
3. Invalid km values: EV charging rows from DKV have misaligned columns —
km position contains a decimal price (e.g. 18.64 EUR or kWh). Added
sanity check: non-integer km values are written as null (empty cell)
instead of a misleading decimal. ExportRow.kilometerstand is now number|null.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -579,15 +579,16 @@ export class DkvService {
|
||||
tenantId: string,
|
||||
vehicles: DkvVehicleBlock[],
|
||||
vehicleFormatString: string,
|
||||
): Promise<{ lieferdatum: string; fahrzeug: string; fahrer: string; ort: string; kilometerstand: number }[]> {
|
||||
): Promise<{ lieferdatum: string; fahrzeug: string; fahrer: string; ort: string; kilometerstand: number | null }[]> {
|
||||
// Batch load vehicle master to avoid N+1 queries
|
||||
const masters = await this.prisma.dkvVehicleMaster.findMany({ where: { tenantId } });
|
||||
const masterMap = new Map(masters.map((m) => [m.kennzeichen, m]));
|
||||
// Normalize keys: DKV PDF may omit hyphens or use spaces ("GP JL 740E" vs "GP-JL 740E")
|
||||
const masterMap = new Map(masters.map((m) => [_normalizeKennzeichen(m.kennzeichen), m]));
|
||||
|
||||
const rows: { lieferdatum: string; fahrzeug: string; fahrer: string; ort: string; kilometerstand: number }[] = [];
|
||||
const rows: { lieferdatum: string; fahrzeug: string; fahrer: string; ort: string; kilometerstand: number | null }[] = [];
|
||||
|
||||
for (const vehicle of vehicles) {
|
||||
const master = masterMap.get(vehicle.kennzeichen);
|
||||
const master = masterMap.get(_normalizeKennzeichen(vehicle.kennzeichen));
|
||||
|
||||
// For unknown plates: use empty string values for unknown fields
|
||||
const vehicleForFormat = {
|
||||
@@ -601,12 +602,20 @@ export class DkvService {
|
||||
const fahrer = master?.fahrer ?? '';
|
||||
|
||||
for (const tx of vehicle.transactions) {
|
||||
// Only keep km values that are plausible odometer readings (whole numbers ≥ 0).
|
||||
// Decimal values indicate a misaligned column (e.g. kWh or EUR from EV charging rows).
|
||||
const rawKm = tx.kilometerstand;
|
||||
const km: number | null =
|
||||
Number.isNaN(rawKm) || !Number.isFinite(rawKm) || !Number.isInteger(rawKm)
|
||||
? null
|
||||
: rawKm;
|
||||
|
||||
rows.push({
|
||||
lieferdatum: tx.lieferdatum,
|
||||
fahrzeug,
|
||||
fahrer,
|
||||
ort: tx.ort,
|
||||
kilometerstand: tx.kilometerstand,
|
||||
kilometerstand: km,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -684,3 +693,12 @@ function _parseVehicleCsv(
|
||||
function _delay(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a Kennzeichen for fuzzy vehicle lookup.
|
||||
* DKV PDF extraction may omit hyphens or use spaces as separators.
|
||||
* Example: "GP JL 740E" == "GP-JL 740E" == "GPJL740E" after normalization.
|
||||
*/
|
||||
function _normalizeKennzeichen(k: string): string {
|
||||
return k.toUpperCase().replace(/[\s\-\.]/g, '');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user