120 lines
4.1 KiB
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,
|
|
]);
|
|
}
|
|
}
|