Steuerkram/tests/34_BankImportDkbTest.php
fds2610-bot aa9ccd1207 Feature: Bank-Import mit konfigurierbaren Formaten, Buchungstext-Templates und Dublettenprüfung
Fix: Dublettenprüfung verwendet nur (buchungstag, wertstellung, wert) ohne buchungstext,
da Vorlagenänderungen sonst zu falschen Duplikaten führen.
2026-05-17 13:47:16 +02:00

145 lines
6.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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');
}
}