Steuerkram/src/Services/VorlageBuchungsService.php

120 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Steuerkram\Services;
use Steuerkram\Database;
use Steuerkram\Models\Account;
use Steuerkram\Models\Beleg;
use Steuerkram\Models\Booking;
use Steuerkram\Models\Buchungsvorlage;
use Steuerkram\Models\Supplier;
class VorlageBuchungsService
{
/**
* Führt alle Buchungen einer Vorlage für einen Beleg aus.
*
* @param int $belegId Ziel-Beleg
* @param int $vorlageId Vorlage
* @param array $inputDaten Formulardaten: ['netto_7'=>..., 'ust_7'=>..., 'zahlungskonto_id'=>..., ...]
* @param string $datum Buchungsdatum (YYYY-MM-DD)
* @return int[] IDs der erstellten Buchungen
*/
public function buchen(int $belegId, int $vorlageId, array $inputDaten, string $datum): array
{
$vorlage = Buchungsvorlage::find($vorlageId);
if (!$vorlage) {
throw new \RuntimeException('Buchungsvorlage nicht gefunden.');
}
$beleg = Beleg::find($belegId);
if (!$beleg) {
throw new \RuntimeException('Beleg nicht gefunden.');
}
if ($beleg['locked']) {
throw new \RuntimeException('Beleg ist gesperrt.');
}
$zahlungskontoId = (int)($inputDaten['zahlungskonto_id'] ?? 0);
if ($zahlungskontoId === 0) {
throw new \RuntimeException('Kein Zahlungskonto gewählt.');
}
$regeln = Buchungsvorlage::getRegeln($vorlageId);
if (empty($regeln)) {
throw new \RuntimeException('Vorlage hat keine Buchungsregeln.');
}
$buchungsIds = [];
Database::beginTransaction();
try {
$this->updateBelegMeta($belegId, $beleg, $inputDaten);
foreach ($regeln as $regel) {
if (!$this->bedingungErfuellt($regel, $inputDaten)) {
continue;
}
foreach ($regel['buchungen'] as $buchung) {
$betrag = round((float)str_replace(',', '.', (string)($inputDaten[$buchung['betrag_ref']] ?? 0)), 2);
if ($betrag == 0.0) {
continue;
}
$nachKonto = Account::findByKontonummer($buchung['nach_konto']);
if (!$nachKonto) {
throw new \RuntimeException("Konto {$buchung['nach_konto']} nicht gefunden.");
}
$buchungsIds[] = Booking::create([
'beleg_id' => $belegId,
'buchungs_datum' => $datum,
'buchungstyp' => 'Ausgabe',
'kategorie_konto_id' => (int)$nachKonto['id'],
'zahlungskonto_id' => $zahlungskontoId,
'betrag_netto' => $betrag,
'ust_satz' => 0,
'steuerart' => 'normal',
'buchungstext' => $vorlage['name'],
]);
}
}
Database::commit();
} catch (\Throwable $e) {
Database::rollBack();
throw $e;
}
return $buchungsIds;
}
private function bedingungErfuellt(array $regel, array $inputDaten): bool
{
$feld = $regel['bedingung_feld'];
$op = $regel['bedingung_op'] ?? 'neq_zero';
if ($op === 'always') {
return true;
}
return round((float)($inputDaten[$feld] ?? 0), 4) != 0.0;
}
private function updateBelegMeta(int $belegId, array $beleg, array $inputDaten): void
{
$supplierId = $beleg['supplier_id'] ?? null;
if (!empty($inputDaten['lieferant'])) {
$supplierId = Supplier::findOrCreate(trim($inputDaten['lieferant']));
}
Beleg::updateMeta($belegId, [
'rechnungs_nr' => $inputDaten['rechnungsnr'] ?? $beleg['rechnungs_nr'] ?? null,
'belegtyp' => $beleg['belegtyp'] ?? 'Eingangsrechnung',
'beleg_datum' => !empty($inputDaten['belegdatum']) ? $inputDaten['belegdatum'] : ($beleg['beleg_datum'] ?? null),
'supplier_id' => $supplierId,
]);
}
}