getMessage();
}
}
foreach ($consistency['unbooked_expense_list'] as $exp) {
try {
create_journal_entry_from_expense((int)$exp['id']);
$fixed_exp++;
} catch (Exception $e) {
$fix_errors[] = 'Ausgabe "' . ($exp['description'] ?? '#' . $exp['id']) . '": ' . $e->getMessage();
}
}
$fix_msg = $fixed_inv . ' Rechnungen und ' . $fixed_exp . ' Ausgaben nachgebucht.';
if ($fix_errors) {
$fix_msg .= ' ' . count($fix_errors) . ' Fehler aufgetreten.';
}
}
// CSV-Export Journal
if (isset($_GET['csv_journal']) && $journal_year) {
$euer = generate_journal_euer((int)$journal_year['id']);
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="eur_' . $year . '.csv"');
$out = fopen('php://output', 'w');
fwrite($out, "\xEF\xBB\xBF");
fputcsv($out, ['EÜR - ' . $year], ';');
fputcsv($out, [], ';');
fputcsv($out, ['Position', 'Betrag'], ';');
fputcsv($out, [], ';');
fputcsv($out, ['EINNAHMEN'], ';');
foreach ($euer['erloese_detail'] as $row) {
fputcsv($out, [$row['name'], number_format((float)$row['total'], 2, ',', '.')], ';');
}
if ($euer['sonstiges_einnahmen'] > 0) {
fputcsv($out, ['Sonstige Einnahmen', number_format($euer['sonstiges_einnahmen'], 2, ',', '.')], ';');
}
fputcsv($out, ['Einnahmen gesamt', number_format($euer['einnahmen_total'], 2, ',', '.')], ';');
fputcsv($out, [], ';');
fputcsv($out, ['AUSGABEN'], ';');
if ($euer['wareneingang'] > 0) {
fputcsv($out, ['Wareneingang', number_format($euer['wareneingang'], 2, ',', '.')], ';');
}
foreach ($euer['aufwand_detail'] as $row) {
fputcsv($out, [$row['name'], number_format((float)$row['total'], 2, ',', '.')], ';');
}
if ($euer['sonstiges_ausgaben'] > 0) {
fputcsv($out, ['Sonstige Ausgaben', number_format($euer['sonstiges_ausgaben'], 2, ',', '.')], ';');
}
fputcsv($out, ['Ausgaben gesamt', number_format($euer['ausgaben_total'], 2, ',', '.')], ';');
fputcsv($out, [], ';');
fputcsv($out, ['STEUER'], ';');
fputcsv($out, ['MwSt (eingenommen)', number_format($euer['mwst'], 2, ',', '.')], ';');
fputcsv($out, ['VorSt (gezahlt)', number_format($euer['vorst'], 2, ',', '.')], ';');
fputcsv($out, ['Steuer-Saldo', number_format($euer['steuer_saldo'], 2, ',', '.')], ';');
fputcsv($out, [], ';');
if ($euer['privat_entnahmen'] > 0 || $euer['privat_einlagen'] > 0) {
fputcsv($out, ['PRIVATKONTEN'], ';');
if ($euer['privat_einlagen'] > 0) {
fputcsv($out, ['Privateinlagen', number_format($euer['privat_einlagen'], 2, ',', '.')], ';');
}
if ($euer['privat_entnahmen'] > 0) {
fputcsv($out, ['Privatentnahmen', number_format($euer['privat_entnahmen'], 2, ',', '.')], ';');
}
fputcsv($out, [], ';');
}
fputcsv($out, ['GEWINN', number_format($euer['gewinn'], 2, ',', '.')], ';');
fclose($out);
exit;
}
// Journal-Daten laden
$journal_euer = null;
if ($journal_year) {
$journal_euer = generate_journal_euer((int)$journal_year['id']);
}
// Konsistenz-Check: Fehlende Buchungen
$consistency = check_journal_consistency();
$has_missing = ($consistency['unbooked_invoices'] > 0 || $consistency['unbooked_expenses'] > 0);
// Verfügbare Jahre sammeln (aus Journal + Rechnungen + Ausgaben)
$available_years = [];
foreach ($years as $y) {
$available_years[(int)$y['year']] = true;
}
$stmt = $pdo->query("SELECT DISTINCT EXTRACT(YEAR FROM invoice_date)::int AS y FROM invoices WHERE paid = TRUE ORDER BY y DESC");
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$available_years[$row['y']] = true;
}
try {
$stmt = $pdo->query("SELECT DISTINCT EXTRACT(YEAR FROM expense_date)::int AS y FROM expenses WHERE paid = TRUE ORDER BY y DESC");
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$available_years[$row['y']] = true;
}
} catch (PDOException $e) {}
krsort($available_years);
$available_years = array_keys($available_years);
if (empty($available_years)) {
$available_years = [$current_cal_year];
}
?>
EÜR = $year ?>
Einnahmen-Überschuss-Rechnung = $year ?>
= htmlspecialchars($fix_msg) ?>
Fehler beim Nachbuchen
- = htmlspecialchars($fe) ?>
Bitte die betroffenen Belege manuell prüfen und ggf. eine Aufwandskategorie zuweisen.
Fehlende Journalbuchungen
Es gibt bezahlte Belege ohne Journaleintrag. Die EÜR ist dadurch unvollständig.
0): ?>
- = $consistency['unbooked_invoices'] ?> bezahlte Rechnung(en) ohne Journalbuchung
0): ?>
- = $consistency['unbooked_expenses'] ?> bezahlte Ausgabe(n) ohne Journalbuchung
Fehlende Buchungen nachholen
Basierend auf Journalbuchungen (Zufluss-/Abflussprinzip)
Einnahmen
| = htmlspecialchars($row['name']) ?> |
= number_format((float)$row['total'], 2, ',', '.') ?> € |
0): ?>
| Sonstige Einnahmen |
= number_format($journal_euer['sonstiges_einnahmen'], 2, ',', '.') ?> € |
| Einnahmen gesamt |
= number_format($journal_euer['einnahmen_total'], 2, ',', '.') ?> € |
Ausgaben
0): ?>
| Wareneingang |
= number_format($journal_euer['wareneingang'], 2, ',', '.') ?> € |
| = htmlspecialchars($row['name']) ?> |
= number_format((float)$row['total'], 2, ',', '.') ?> € |
0): ?>
| Sonstige Ausgaben |
= number_format($journal_euer['sonstiges_ausgaben'], 2, ',', '.') ?> € |
| Ausgaben gesamt |
= number_format($journal_euer['ausgaben_total'], 2, ',', '.') ?> € |
Steuer
| MwSt (eingenommen) |
= number_format($journal_euer['mwst'], 2, ',', '.') ?> € |
| VorSt (gezahlt) |
= number_format($journal_euer['vorst'], 2, ',', '.') ?> € |
| Steuer-Saldo |
= number_format($journal_euer['steuer_saldo'], 2, ',', '.') ?> € |
0 || $journal_euer['privat_einlagen'] > 0): ?>
Privatkonten
0): ?>
| Privateinlagen |
= number_format($journal_euer['privat_einlagen'], 2, ',', '.') ?> € |
0): ?>
| Privatentnahmen |
= number_format($journal_euer['privat_entnahmen'], 2, ',', '.') ?> € |
Ergebnis
| Gewinn / Verlust |
= number_format($journal_euer['gewinn'], 2, ',', '.') ?> € |
Kein Journal für = $year ?> vorhanden.
Klicke oben auf "Fehlende Buchungen nachholen" um das Journal automatisch zu erstellen.
Jahr im Journal anlegen