import { describe, expect, it } from 'vitest'; import { validateKantinenData } from './kantine-csv.validator'; import type { KantinenRawRow } from './kantine-datev.types'; function row(over: Partial = {}): KantinenRawRow { return { personalNr: '100', name: 'Max Muster', menge: '1', ekPreis: '1,00', netto: '1,00', zuAbschlag: '0', mwst: '0', zuschuss: '0', betrag: '7,94', abrechnungVon: '01.03.2026', abrechnungBis: '31.03.2026', ...over, }; } describe('validateKantinenData', () => { it('akzeptiert eine gueltige Zeile und bestimmt den Monat aus "bis"', () => { const result = validateKantinenData([row()]); expect(result.isValid).toBe(true); expect(result.abrechnungsMonat).toBe('03/2026'); }); it('meldet nicht numerische und fehlende Personalnummern', () => { const r = validateKantinenData([row({ personalNr: 'A12' }), row({ personalNr: '' })]); expect(r.errors.map((e) => e.code)).toEqual(['personalNrNotNumeric', 'personalNrMissing']); expect(r.errors[0].message).toBe('Personalnummer muss numerisch sein'); }); it('lehnt Betraege mit Tausenderpunkt oder Minus ab (wie die Vorlage)', () => { const r = validateKantinenData([ row({ betrag: '1.234,56' }), row({ betrag: '-5,00' }), row({ betrag: '' }), ]); expect(r.errors.map((e) => e.code)).toEqual(['betragFormat', 'betragFormat', 'betragMissing']); }); it('prueft das Datumsformat', () => { const r = validateKantinenData([row({ abrechnungVon: '2026-03-01', abrechnungBis: '' })]); expect(r.errors.map((e) => e.code)).toEqual(['vonFormat', 'bisMissing']); }); it('meldet von/bis in verschiedenen Monaten mit Zeile = Index + 2', () => { const r = validateKantinenData([row(), row({ abrechnungVon: '28.02.2026' })]); expect(r.errors).toEqual([ expect.objectContaining({ row: 3, code: 'multiMonthRange', field: 'abrechnungVon/abrechnungBis', }), ]); }); it('nimmt die echte Dateizeile, wenn der Parser sie mitliefert', () => { const r = validateKantinenData([row({ personalNr: 'x', line: 9 })]); expect(r.errors[0].row).toBe(9); }); it('warnt bei zwei Abrechnungsmonaten und behaelt den ersten', () => { const r = validateKantinenData([ row(), row({ abrechnungVon: '01.04.2026', abrechnungBis: '30.04.2026' }), ]); expect(r.isValid).toBe(true); expect(r.abrechnungsMonat).toBe('03/2026'); expect(r.warnings).toHaveLength(1); expect(r.warnings[0]).toMatchObject({ code: 'multipleMonths', params: { months: ['03/2026', '04/2026'] }, }); expect(r.warnings[0].message).toBe( 'Verschiedene Abrechnungsmonate erkannt: 03/2026, 04/2026. Alle Zeilen sollten im selben Abrechnungsmonat liegen.', ); }); });