prepare("SELECT COUNT(*) FROM invoices WHERE paid = FALSE");
$stmt->execute();
$open_invoices_count = (int)$stmt->fetchColumn();
$stmt = $pdo->prepare("SELECT COALESCE(SUM(total_gross),0) FROM invoices WHERE paid = FALSE");
$stmt->execute();
$open_invoices_sum = (float)$stmt->fetchColumn();
// Überfällige Rechnungen (> 14 Tage offen)
$stmt = $pdo->prepare("SELECT i.*, c.name AS customer_name FROM invoices i JOIN customers c ON c.id = i.customer_id WHERE i.paid = FALSE AND i.invoice_date < NOW() - INTERVAL '14 days' ORDER BY i.invoice_date ASC LIMIT 5");
$stmt->execute();
$overdue_invoices = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Fällige Abo-Rechnungen
$pending_recurring = count_pending_recurring_invoices();
// Konsistenz-Check: Fehlende Buchungen
$consistency = check_journal_consistency();
$has_unbooked = ($consistency['unbooked_invoices'] > 0 || $consistency['unbooked_expenses'] > 0);
// GoBD PDF-Status
$gobd_status = check_pdf_integrity_status();
$gobd_has_problems = ($gobd_status['unarchived'] > 0 || $gobd_status['invalid'] > 0 || $gobd_status['missing_files'] > 0);
// Letzte 5 Rechnungen
$stmt = $pdo->prepare("SELECT i.*, c.name AS customer_name FROM invoices i JOIN customers c ON c.id = i.customer_id ORDER BY i.created_at DESC LIMIT 5");
$stmt->execute();
$recent_invoices = $stmt->fetchAll(PDO::FETCH_ASSOC);
// === JOURNAL MODUL ===
$journal_year = get_journal_year_by_year((int)$year);
$journal_year_id = $journal_year ? (int)$journal_year['id'] : null;
$journal_erloese_monat = 0;
$journal_wareneingang_monat = 0;
$journal_gewinn_monat = 0;
$journal_erloese_jahr = 0;
$journal_wareneingang_jahr = 0;
$journal_gewinn_jahr = 0;
$journal_entries_month = 0;
$journal_gewinn_prev = 0;
if ($journal_year_id) {
$month_profit = calculate_yearly_profitability($journal_year_id);
if (isset($month_profit[$month])) {
$journal_erloese_monat = $month_profit[$month]['erloese'];
$journal_wareneingang_monat = $month_profit[$month]['wareneingang'];
$journal_gewinn_monat = $month_profit[$month]['gewinn'];
}
if (isset($month_profit[$prev_month])) {
$journal_gewinn_prev = $month_profit[$prev_month]['gewinn'];
}
foreach ($month_profit as $m => $p) {
$journal_erloese_jahr += $p['erloese'];
$journal_wareneingang_jahr += $p['wareneingang'];
$journal_gewinn_jahr += $p['gewinn'];
}
$stmt = $pdo->prepare("SELECT COUNT(*) FROM journal_entries WHERE year_id = :y AND month = :m");
$stmt->execute([':y' => $journal_year_id, ':m' => $month]);
$journal_entries_month = (int)$stmt->fetchColumn();
$mt = calculate_monthly_totals($journal_year_id, $month);
$journal_kasse_balance = ($mt['kasse_s'] ?? 0) - ($mt['kasse_h'] ?? 0);
$journal_bank_balance = ($mt['bank_s'] ?? 0) - ($mt['bank_h'] ?? 0);
} else {
$journal_kasse_balance = 0;
$journal_bank_balance = 0;
}
// Sparkline-Daten
$sparkline_erloese = [];
$sparkline_gewinn = [];
$sparkline_wareneingang = [];
if ($journal_year_id && !empty($month_profit)) {
for ($m = 1; $m <= $month; $m++) {
$sparkline_erloese[] = $month_profit[$m]['erloese'] ?? 0;
$sparkline_gewinn[] = $month_profit[$m]['gewinn'] ?? 0;
$sparkline_wareneingang[] = $month_profit[$m]['wareneingang'] ?? 0;
}
}
// Letzte 5 Journal-Einträge
$recent_journal = get_recent_journal_entries(5);
$month_names_full = [
1 => 'Januar', 2 => 'Februar', 3 => 'März', 4 => 'April',
5 => 'Mai', 6 => 'Juni', 7 => 'Juli', 8 => 'August',
9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Dezember',
];
?>
PIRP Dashboard
Fehlende Journalbuchungen:
0): ?>
= $consistency['unbooked_invoices'] ?> bezahlte Rechnung(en)
0 && $consistency['unbooked_expenses'] > 0): ?> und
0): ?>
= $consistency['unbooked_expenses'] ?> bezahlte Ausgabe(n)
ohne Journaleintrag.
Jetzt nachholen
= htmlspecialchars($year) ?> · = $month_names_full[$month] ?>
Offen
= number_format($open_invoices_sum, 2, ',', '.') ?> €
= $open_invoices_count ?> Rechnungen
Abo-Rechnungen
= $pending_recurring ?> fällig
0): ?>
Generieren
Erlöse (Jahr)
= number_format($journal_erloese_jahr, 2, ',', '.') ?> €
= 2): ?>
= generate_sparkline_svg($sparkline_erloese, '#22c55e') ?>
Jahresübersicht →
Gewinn (Jahr)
>= number_format($journal_gewinn_jahr, 2, ',', '.') ?> €
= 2): ?>
= generate_sparkline_svg($sparkline_gewinn, '#d4882a') ?>
EÜR →
Erlöse
= number_format($journal_erloese_monat, 2, ',', '.') ?> €
= $gwdiff >= 0 ? '+' : '' ?>= number_format($gwdiff, 2, ',', '.') ?> Gewinn gg. Vormonat
Gewinn
>= number_format($journal_gewinn_monat, 2, ',', '.') ?> €
= 2): ?>
= generate_sparkline_svg($sparkline_wareneingang, '#737373') ?>
Kasse
= number_format($journal_kasse_balance, 2, ',', '.') ?> €
Journal →
Bank
= number_format($journal_bank_balance, 2, ',', '.') ?> €
+ Neue Buchung
Monatsvergleich = $year ?>
= generate_monthly_bar_chart_svg($month_profit, $month) ?>
Offen
= number_format($open_invoices_sum, 2, ',', '.') ?> €
= $open_invoices_count ?> Rechnungen
Abo-Rechnungen
= $pending_recurring ?> fällig
0): ?>
Generieren
Überfällige Rechnungen
| Datum |
Nr. |
Kunde |
Betrag |
Tage offen |
| = date('d.m.Y', strtotime($oi['invoice_date'])) ?> |
= htmlspecialchars($oi['invoice_number']) ?> |
= htmlspecialchars($oi['customer_name']) ?> |
= number_format((float)$oi['total_gross'], 2, ',', '.') ?> € |
= $days ?> Tage |
Letzte Rechnungen
| Datum | Kunde | Betrag | Status |
| = date('d.m', strtotime($ri['invoice_date'])) ?> |
= htmlspecialchars($ri['customer_name']) ?> |
= number_format((float)$ri['total_gross'], 2, ',', '.') ?> |
= $ri['paid'] ? 'bezahlt' : 'offen' ?> |
| Keine Rechnungen |
Alle Rechnungen
GoBD-Warnung: PDF-Archivierung unvollständig
0): ?>
- = $gobd_status['unarchived'] ?> Rechnung(en) ohne archivierte PDF
0): ?>
- = $gobd_status['missing_files'] ?> PDF-Datei(en) fehlen auf dem Server
0): ?>
- = $gobd_status['invalid'] ?> PDF(s) mit fehlgeschlagener Integritätsprüfung
Betroffene Rechnungen anzeigen
| Rechnungsnr. | Problem | Aktion |
| = htmlspecialchars($prob['invoice_number']) ?> |
= htmlspecialchars($prob['message']) ?> |
PDF neu generieren |
10): ?>
| ... und = count($gobd_status['problems']) - 10 ?> weitere |
Datenbank-Migration erforderlich:
1. sudo -u postgres psql -d pirp -f /var/www/pirp/tools/migrate_pdf.sql
2. php /var/www/pirp/tools/run_migration.php
0): ?>
Migration: php tools/run_migration.php
GoBD OK:
= $gobd_status['archived'] ?>/= $gobd_status['total_invoices'] ?> archiviert.