mandantAnlegen(); $this->giro = Konto::anlegen([ 'name' => 'KL Giro', 'kontoart' => 'bank', 'anfangssaldo' => 10000, 'aktiv' => 1, ]); $this->depot = Konto::anlegen([ 'name' => 'KL Depot', 'kontoart' => 'depot', 'anfangssaldo' => 0, 'aktiv' => 1, ]); $this->klasse = Klasse::anlegen('KL Altersvorsorge'); $this->andereKlasse = Klasse::anlegen('KL Haushalt'); Einstellung::set( Wertpapierkosten::schluessel('bankprovision'), (string)Kategorie::anlegen(['name' => 'KL Bankprovision', 'art' => 'ausgabe']), 'wertpapiere' ); $this->geschaeftOhneKosten(); $this->geschaeftMitKosten(); $this->leereAuswahlLoeschtDieKlasse(); $this->ohneAngabeBleibtDieKlasse(); $this->unbekannteKlasse(); $this->depotbuchungMitGeldbuchung(); } private function buchung(float $betrag, string $datum, ?int $klasse = null): int { return Buchung::anlegen([ 'konto_id' => $this->giro, 'datum' => $datum, 'betrag' => $betrag, 'klasse_id' => $klasse, 'quelle' => 'banking', ]); } private function geschaeftOhneKosten(): void { $id = $this->buchung(-500.0, '2026-09-01'); Wertpapiergeschaeft::buchen(Buchung::find($id), [ 'depot_id' => $this->depot, 'wertpapier_name' => 'KL Ohne Kosten AG', 'stueck' => 5, 'klasse_id' => $this->klasse, ]); $buchung = Buchung::find($id); $this->assertEquals($this->depot, (int)$buchung['gegenkonto_id'], 'Die Umbuchung ins Depot entsteht'); $this->assertEquals($this->klasse, (int)$buchung['klasse_id'], 'Die gewählte Klasse steht an der Buchung'); } private function geschaeftMitKosten(): void { $id = $this->buchung(-255.0, '2026-09-02'); Wertpapiergeschaeft::buchen(Buchung::find($id), [ 'depot_id' => $this->depot, 'wertpapier_name' => 'KL Mit Kosten AG', 'stueck' => 2, 'kosten' => ['bankprovision' => 5.0], 'klasse_id' => $this->klasse, ]); $buchung = Buchung::find($id); $this->assertEquals($this->klasse, (int)$buchung['klasse_id'], 'Auch die Splitbuchung trägt die Klasse'); $splits = Buchung::splits($id); $this->assertEquals(2, count($splits), 'Depot und Bankprovision'); foreach ($splits as $nr => $zeile) { $this->assertEquals($this->klasse, (int)$zeile['klasse_id'], 'Splitzeile ' . $nr . ' trägt die Klasse'); } $anzeige = Buchung::splitKlasse($splits, (int)$buchung['klasse_id']); $this->assert(!$anzeige['gemischt'], 'Das Kontoblatt zeigt keine gemischten Klassen'); $this->assertEquals($this->klasse, $anzeige['klasse_id'], 'Sondern die eine gewählte Klasse'); } /** Die Maske ist mit der Klasse der Buchung vorbelegt – leer heißt: keine. */ private function leereAuswahlLoeschtDieKlasse(): void { $id = $this->buchung(-100.0, '2026-09-03', $this->andereKlasse); Wertpapiergeschaeft::buchen(Buchung::find($id), [ 'depot_id' => $this->depot, 'wertpapier_name' => 'KL Leer AG', 'stueck' => 1, 'klasse_id' => null, ]); $this->assertNull(Buchung::find($id)['klasse_id'], 'Die leere Auswahl entfernt die Klasse'); } private function ohneAngabeBleibtDieKlasse(): void { $id = $this->buchung(-110.0, '2026-09-04', $this->andereKlasse); Wertpapiergeschaeft::buchen(Buchung::find($id), [ 'depot_id' => $this->depot, 'wertpapier_name' => 'KL Ohne Angabe AG', 'stueck' => 1, 'kosten' => ['bankprovision' => 10.0], ]); $this->assertEquals( $this->andereKlasse, (int)Buchung::find($id)['klasse_id'], 'Ohne Angabe bleibt die Klasse der Buchung' ); foreach (Buchung::splits($id) as $zeile) { $this->assertEquals($this->andereKlasse, (int)$zeile['klasse_id'], 'Und die Splitzeilen übernehmen sie'); } } private function unbekannteKlasse(): void { $id = $this->buchung(-120.0, '2026-09-05'); $abgewiesen = false; try { Wertpapiergeschaeft::buchen(Buchung::find($id), [ 'depot_id' => $this->depot, 'wertpapier_name' => 'KL Unbekannt AG', 'stueck' => 1, 'klasse_id' => 999999999, ]); } catch (\InvalidArgumentException $e) { $abgewiesen = true; } $this->assert($abgewiesen, 'Eine unbekannte Klasse wird abgewiesen'); $this->assertNull(Depotbuchung::findeZuBuchung($id), 'Und es entsteht kein Geschäft'); } /** Die Depotbuchung unter Wertpapiere legt die Geldbuchung selbst an. */ private function depotbuchungMitGeldbuchung(): void { $papier = Wertpapier::findenOderAnlegen(['name' => 'KL Depot AG', 'isin' => 'DE000KL00001']); $depotbuchungId = Depotbuchung::anlegen([ 'konto_id' => $this->depot, 'wertpapier_id' => $papier, 'datum' => '2026-09-06', 'vorgang' => 'kauf', 'stueck' => 10, 'kurs' => 20, 'betrag' => 200, 'verrechnungskonto_id' => $this->giro, 'klasse_id' => $this->klasse, ]); $geldbuchung = Buchung::find((int)Depotbuchung::find($depotbuchungId)['buchung_id']); $this->assertNotEmpty($geldbuchung, 'Die Geldbuchung entsteht'); $this->assertEquals($this->klasse, (int)$geldbuchung['klasse_id'], 'Mit der gewählten Klasse'); $abgewiesen = false; try { Depotbuchung::anlegen([ 'konto_id' => $this->depot, 'wertpapier_id' => $papier, 'datum' => '2026-09-07', 'vorgang' => 'kauf', 'stueck' => 1, 'betrag' => 20, 'verrechnungskonto_id' => $this->giro, 'klasse_id' => 999999999, ]); } catch (\InvalidArgumentException $e) { $abgewiesen = true; } $this->assert($abgewiesen, 'Auch hier wird eine unbekannte Klasse abgewiesen'); } }