Fix: Dublettenprüfung verwendet nur (buchungstag, wertstellung, wert) ohne buchungstext, da Vorlagenänderungen sonst zu falschen Duplikaten führen.
145 lines
6.2 KiB
PHP
145 lines
6.2 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* Test 34: BankImportParser – DKB-Format mit Template-basiertem Buchungstext.
|
||
*/
|
||
class BankImportDkbTest extends TestCase
|
||
{
|
||
protected string $testName = 'Test 34: BankImportParser – DKB-Format (Template)';
|
||
|
||
private function makeTempCsv(string $content): string
|
||
{
|
||
$path = sys_get_temp_dir() . '/test34_' . uniqid() . '.csv';
|
||
file_put_contents($path, $content);
|
||
return $path;
|
||
}
|
||
|
||
private function dkbFormat(): array
|
||
{
|
||
return [
|
||
'skip_rows' => 4,
|
||
'has_header_row' => 1,
|
||
'delimiter' => ';',
|
||
'enclosure' => '"',
|
||
'col_buchungstag' => 0,
|
||
'col_wertstellung' => 1,
|
||
'col_vorgang' => 6,
|
||
'col_buchungstext' => 5,
|
||
'col_wert' => 8,
|
||
'buchungstext_template_debit' => 'Auftraggeber: {Zahlungsempfänger*in} Buchungstext: {Verwendungszweck}',
|
||
'buchungstext_template_credit' => 'Auftraggeber: {Zahlungspflichtige*r} Buchungstext: {Verwendungszweck}',
|
||
'date_format' => 'd.m.Y',
|
||
'decimal_separator' => ',',
|
||
'thousands_separator' => '.',
|
||
];
|
||
}
|
||
|
||
private function dkbHeader(): string
|
||
{
|
||
return '"Buchungsdatum";"Wertstellung";"Status";"Zahlungspflichtige*r";'
|
||
. '"Zahlungsempfänger*in";"Verwendungszweck";"Umsatztyp";"IBAN";"Betrag (€)";'
|
||
. '"Gläubiger-ID";"Mandatsreferenz";"Kundenreferenz"';
|
||
}
|
||
|
||
public function run(): void
|
||
{
|
||
$parser = new \Steuerkram\Services\BankImportParser();
|
||
$fmt = $this->dkbFormat();
|
||
|
||
// ── Negativer Betrag: Zahlungsempfänger*in im Buchungstext ───────
|
||
$csv = "Skip1\nSkip2\nSkip3\nSkip4\n"
|
||
. $this->dkbHeader() . "\n"
|
||
. '"15.05.2026";"15.05.2026";"Gebucht";"Max Muster";"Amazon GmbH";"Abo Monatsbeitrag";"Lastschrift";"DE123";"- 9,99";"GL01";"MR01";"KR01"' . "\n";
|
||
|
||
$tmp = $this->makeTempCsv($csv);
|
||
$rows = $parser->parse($tmp, 'csv', $fmt);
|
||
unlink($tmp);
|
||
|
||
$this->assertEquals(1, count($rows), 'DKB negativer Betrag: 1 Buchung geparst');
|
||
$this->assertEquals('2026-05-15', $rows[0]['buchungstag'], 'Buchungstag korrekt');
|
||
$this->assertEquals('2026-05-15', $rows[0]['wertstellung'], 'Wertstellung korrekt');
|
||
$this->assertEquals('Lastschrift', $rows[0]['vorgang'], 'Umsatztyp als vorgang');
|
||
$this->assertEquals(-9.99, $rows[0]['wert'], 'Betrag -9,99 korrekt');
|
||
$this->assertEquals(
|
||
'Auftraggeber: Amazon GmbH Buchungstext: Abo Monatsbeitrag',
|
||
$rows[0]['buchungstext'],
|
||
'Negativer Betrag: Template debit mit Zahlungsempfänger*in'
|
||
);
|
||
|
||
// ── Positiver Betrag: Zahlungspflichtige*r im Buchungstext ───────
|
||
$csv2 = "Skip1\nSkip2\nSkip3\nSkip4\n"
|
||
. $this->dkbHeader() . "\n"
|
||
. '"14.05.2026";"14.05.2026";"Gebucht";"Kunde AG";"Eigenkonto";"Rechnung 2026-042";"Gutschrift";"DE456";"1.500,00";"";"";"KR02"' . "\n";
|
||
|
||
$tmp2 = $this->makeTempCsv($csv2);
|
||
$rows2 = $parser->parse($tmp2, 'csv', $fmt);
|
||
unlink($tmp2);
|
||
|
||
$this->assertEquals(1, count($rows2), 'DKB positiver Betrag: 1 Buchung geparst');
|
||
$this->assertEquals(1500.00, $rows2[0]['wert'], 'Betrag 1.500,00 korrekt');
|
||
$this->assertEquals(
|
||
'Auftraggeber: Kunde AG Buchungstext: Rechnung 2026-042',
|
||
$rows2[0]['buchungstext'],
|
||
'Positiver Betrag: Template credit mit Zahlungspflichtige*r'
|
||
);
|
||
|
||
// ── Betrag 0: credit-Template (>= 0) ────────────────────────────
|
||
$csv3 = "Skip1\nSkip2\nSkip3\nSkip4\n"
|
||
. $this->dkbHeader() . "\n"
|
||
. '"13.05.2026";"13.05.2026";"Gebucht";"Nullbetrag GmbH";"Gegenkonto";"Storno";"Umbuchung";"DE789";"0,00";"";"";"KR03"' . "\n";
|
||
|
||
$tmp3 = $this->makeTempCsv($csv3);
|
||
$rows3 = $parser->parse($tmp3, 'csv', $fmt);
|
||
unlink($tmp3);
|
||
|
||
$this->assertEquals(1, count($rows3), 'DKB Betrag 0: 1 Buchung geparst');
|
||
$this->assertEquals(
|
||
'Auftraggeber: Nullbetrag GmbH Buchungstext: Storno',
|
||
$rows3[0]['buchungstext'],
|
||
'Betrag 0: credit-Template genutzt'
|
||
);
|
||
|
||
// ── Unbekannte Placeholder werden als leer aufgelöst ─────────────
|
||
$fmtUnknown = $fmt;
|
||
$fmtUnknown['buchungstext_template_debit'] = 'Test: {NichtVorhanden} Ende';
|
||
$csv5 = "Skip1\nSkip2\nSkip3\nSkip4\n"
|
||
. $this->dkbHeader() . "\n"
|
||
. '"12.05.2026";"12.05.2026";"Gebucht";"A";"B";"C";"Lastschrift";"DE";"- 1,00";"";"";"KR05"' . "\n";
|
||
|
||
$tmp5 = $this->makeTempCsv($csv5);
|
||
$rows5 = $parser->parse($tmp5, 'csv', $fmtUnknown);
|
||
unlink($tmp5);
|
||
|
||
$this->assertEquals('Test: Ende', $rows5[0]['buchungstext'],
|
||
'Unbekannter Placeholder wird als leerer String aufgelöst');
|
||
|
||
// ── Format ohne Template: col_buchungstext wird direkt genutzt ───
|
||
$fmtStd = [
|
||
'skip_rows' => 3,
|
||
'has_header_row' => 1,
|
||
'delimiter' => ';',
|
||
'enclosure' => '"',
|
||
'col_buchungstag' => 0,
|
||
'col_wertstellung' => 1,
|
||
'col_vorgang' => 2,
|
||
'col_buchungstext' => 3,
|
||
'col_wert' => 4,
|
||
'date_format' => 'd.m.Y',
|
||
'decimal_separator' => ',',
|
||
'thousands_separator' => '.',
|
||
];
|
||
|
||
$csv4 = "Z1\nZ2\nZ3\n"
|
||
. "Buchungstag;Wertstellung;Vorgang;Buchungstext;Betrag\n"
|
||
. "15.05.2026;15.05.2026;Lastschrift;Normaler Text;\"-50,00\"\n";
|
||
|
||
$tmp4 = $this->makeTempCsv($csv4);
|
||
$rows4 = $parser->parse($tmp4, 'csv', $fmtStd);
|
||
unlink($tmp4);
|
||
|
||
$this->assertEquals('Normaler Text', $rows4[0]['buchungstext'],
|
||
'Format ohne Template: col_buchungstext direkt genutzt');
|
||
}
|
||
}
|