kategorieId = (int)$this->findAccountId('4855'); $this->zahlungsId = (int)$this->findAccountId('0420'); $this->assetId = Asset::create([ 'bezeichnung' => 'Testgerät AfA-Modell', 'anschaffungsdatum' => '2024-01-15', 'anschaffungskosten' => 1200.00, 'zugaenge' => 0, 'abgaenge' => 0, 'abschreibung_jahr' => 400.00, 'nutzungsdauer' => 3, 'account_id' => $this->zahlungsId, ]); $this->gesperrtesJahrLehntAfaBuchungAb(); $this->afaBuchungInOffenemJahr(); $this->stornoUebernimmtJahrDerOriginalbuchung(); $this->gesperrtesJahrLehntStornoAb(); } private function gesperrtesJahrLehntAfaBuchungAb(): void { $jahr = 2019; $fy = FiscalYear::findOrCreateByYear($jahr); \Steuerkram\Database::execute('UPDATE fiscal_years SET locked = 1 WHERE id = ?', [$fy['id']]); $vorher = $this->countBookings(); $exception = null; try { Booking::createAfa($this->afaData($jahr)); } catch (\RuntimeException $e) { $exception = $e; } $this->assert($exception !== null, 'AfA-Buchung in gesperrtem Geschäftsjahr wirft eine RuntimeException'); $this->assertEquals( $vorher, $this->countBookings(), 'Bei Sperre wird kein Datensatz in bookings angelegt' ); } private function afaBuchungInOffenemJahr(): void { $jahr = 2024; $bookingId = Booking::createAfa($this->afaData($jahr)); $this->assertGreaterThan(0, $bookingId, 'AfA-Buchung in offenem Jahr wird angelegt'); $booking = Booking::find($bookingId); $this->assertEquals($jahr, (int)$booking['afa_jahr'], 'afa_jahr ist gesetzt'); $this->assertEquals($jahr . '-12-31', $booking['buchungs_datum'], 'buchungs_datum liegt auf dem 31.12. des AfA-Jahres'); $this->assertEquals(0.00, (float)$booking['betrag_ust'], 'betrag_ust ist 0'); $this->assertEquals(400.00, (float)$booking['betrag_netto'], 'betrag_netto entspricht dem AfA-Betrag'); $this->assert( (bool)preg_match('/^AFA-\d{5}$/', $booking['buchungs_nr']), 'Buchungsnummer folgt dem Schema AFA-NNNNN (erhalten: ' . $booking['buchungs_nr'] . ')' ); } private function stornoUebernimmtJahrDerOriginalbuchung(): void { // Vorjahr: 2022 – das laufende Kalenderjahr ist ein anderes. $jahr = 2022; $bookingId = Booking::createAfa($this->afaData($jahr)); $original = Booking::find($bookingId); $reversalId = Booking::reverseAfa($bookingId); $reversal = Booking::find($reversalId); $this->assertEquals( $original['fiscal_year_id'], $reversal['fiscal_year_id'], 'Storno erhält die fiscal_year_id der Originalbuchung, nicht die des aktuellen Jahres' ); $aktuellesJahr = FiscalYear::findOrCreateByYear((int)date('Y')); $this->assert( (int)$reversal['fiscal_year_id'] !== (int)$aktuellesJahr['id'], 'fiscal_year_id des Storno ist nicht die des laufenden Kalenderjahres' ); $this->assertEquals(1, (int)$reversal['is_reversal'], 'Stornobuchung ist als is_reversal=1 markiert'); $updatedOriginal = Booking::find($bookingId); $this->assertEquals( $reversalId, (int)$updatedOriginal['reversed_by'], 'reversed_by der Originalbuchung zeigt auf die Stornobuchung' ); $this->assert( (bool)preg_match('/^AFA-\d{5}$/', $reversal['buchungs_nr']), 'Storno-Buchungsnummer folgt ebenfalls dem Schema AFA-NNNNN' ); } private function gesperrtesJahrLehntStornoAb(): void { $jahr = 2020; $bookingId = Booking::createAfa($this->afaData($jahr)); $fy = FiscalYear::findByYear($jahr); \Steuerkram\Database::execute('UPDATE fiscal_years SET locked = 1 WHERE id = ?', [$fy['id']]); $vorher = $this->countBookings(); $exception = null; try { Booking::reverseAfa($bookingId); } catch (\RuntimeException $e) { $exception = $e; } $this->assert($exception !== null, 'Storno einer AfA-Buchung im gesperrten Jahr wirft eine RuntimeException'); $this->assertEquals( $vorher, $this->countBookings(), 'Bei Sperre wird kein zusätzlicher Storno-Datensatz angelegt' ); $unverändert = Booking::find($bookingId); $this->assert(empty($unverändert['reversed_by']), 'Originalbuchung bleibt ohne reversed_by, wenn das Storno abgelehnt wird'); } private function afaData(int $jahr): array { return [ 'asset_id' => $this->assetId, 'afa_jahr' => $jahr, 'kategorie_konto_id' => $this->kategorieId, 'zahlungskonto_id' => $this->zahlungsId, 'betrag' => 400.00, 'buchungstext' => 'AfA Test ' . $jahr, ]; } private function countBookings(): int { $row = \Steuerkram\Database::fetchOne('SELECT COUNT(*) as cnt FROM bookings'); return (int)($row['cnt'] ?? 0); } }