`. Einmal hinterlegt, fragt der * Kostendialog nur noch Beträge ab. Einzige Ausnahme ist „Sonstige Kosten“: * Deren Kategorie lässt sich im Dialog wählen, weil sie eben nicht immer * dieselbe ist – so hält es auch der FinanzManager. */ class Wertpapierkosten { /** Gebührenarten in der Reihenfolge des Dialogs. */ public const GEBUEHREN = [ 'bankprovision' => 'Bankprovision', 'maklercourtage' => 'Maklercourtage', 'boersenplatzentgelt' => 'Börsenplatzentgelt', 'spesen' => 'Spesen', 'spesen_ausland' => 'Spesen Ausland', 'sonstige' => 'Sonstige Kosten', ]; /** Steuerarten in der Reihenfolge des Dialogs. */ public const STEUERN = [ 'zinsabschlagsteuer' => 'Zinsabschlagsteuer', 'kapitalertragsteuer' => 'Kapitalertragsteuer', 'solidaritaetszuschlag' => 'Solidaritätszuschlag', 'quellensteuer' => 'Ausländische Quellensteuer', 'abgeltungsteuer' => 'Abgeltungsteuer', 'kirchensteuer' => 'Kirchensteuer', ]; /** Die eine Art, deren Kategorie im Dialog steht statt in den Einstellungen. */ public const SONSTIGE = 'sonstige'; /** @return array art => Beschriftung, Gebühren vor Steuern */ public static function arten(): array { return self::GEBUEHREN + self::STEUERN; } public static function istSteuer(string $art): bool { return array_key_exists($art, self::STEUERN); } /** Der Einstellungsschlüssel zu einer Kostenart. */ public static function schluessel(string $art): string { return 'wertpapiere_kategorie_' . $art; } /** * Die hinterlegten Kategorien, auch die leeren. * * @return array */ public static function kategorien(): array { $kategorien = []; foreach (array_keys(self::arten()) as $art) { $wert = (int)Einstellung::get(self::schluessel($art), ''); $kategorien[$art] = $wert > 0 ? $wert : null; } return $kategorien; } /** * Die belegten Kostenzeilen eines Geschäfts, fertig für die Splitbuchung. * * Beträge werden auf ihren Betrag ohne Vorzeichen gebracht: Nebenkosten * sind immer Aufwand – beim Kauf wie beim Verkauf –, und das Vorzeichen der * Splitzeile setzt erst der Aufrufer. * * @param array $betraege art => Betrag * @param ?int $sonstigeKategorie Kategorie für „Sonstige Kosten“ * @return list */ public static function zeilen(array $betraege, ?int $sonstigeKategorie = null): array { $kategorien = self::kategorien(); $zeilen = []; foreach (self::arten() as $art => $name) { $betrag = round(abs((float)($betraege[$art] ?? 0.0)), 2); if ($betrag < 0.005) { continue; } $kategorie = $art === self::SONSTIGE && $sonstigeKategorie !== null ? $sonstigeKategorie : $kategorien[$art]; $zeilen[] = [ 'art' => $art, 'name' => $name, 'betrag' => $betrag, 'kategorie_id' => $kategorie, 'steuer' => self::istSteuer($art), ]; } return $zeilen; } /** * Gebühren- und Steuersumme der Zeilen – so, wie die Depotbuchung sie führt. * * @param list $zeilen * @return array{gebuehren:float,steuern:float,summe:float} */ public static function summen(array $zeilen): array { $gebuehren = 0.0; $steuern = 0.0; foreach ($zeilen as $zeile) { if ($zeile['steuer']) { $steuern += $zeile['betrag']; } else { $gebuehren += $zeile['betrag']; } } return [ 'gebuehren' => round($gebuehren, 2), 'steuern' => round($steuern, 2), 'summe' => round($gebuehren + $steuern, 2), ]; } }