beginTransaction();
try {
// Bezahlt-Status und Zahlungsdatum setzen
$stmt = $pdo->prepare('UPDATE invoices SET paid = TRUE, payment_date = :pd WHERE id = :id');
$stmt->execute([':id' => $id, ':pd' => $payment_date]);
// Automatisch Journalbuchung erstellen
$existing = get_journal_entry_for_invoice($id);
if (!$existing) {
$entry_id = create_journal_entry_from_invoice($id);
$msg = 'Rechnung als bezahlt markiert. Journalbuchung #' . $entry_id . ' erstellt.';
} else {
$msg = 'Rechnung als bezahlt markiert (Journalbuchung existierte bereits).';
}
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
$msg = 'Fehler: ' . $e->getMessage();
}
header('Location: ' . url_for('invoices.php?msg=' . urlencode($msg)));
exit;
}
// Nachricht aus Redirect anzeigen
if (isset($_GET['msg'])) {
$msg = $_GET['msg'];
}
$filter_number = trim($_GET['number'] ?? '');
$filter_customer = trim($_GET['customer'] ?? '');
$filter_from = trim($_GET['from'] ?? '');
$filter_to = trim($_GET['to'] ?? '');
$where = "WHERE 1=1";
$params = [];
if ($filter_number !== '') {
$where .= " AND i.invoice_number ILIKE :num";
$params[':num'] = '%' . $filter_number . '%';
}
if ($filter_customer !== '') {
$where .= " AND c.name ILIKE :cust";
$params[':cust'] = '%' . $filter_customer . '%';
}
if ($filter_from !== '') {
$where .= " AND i.invoice_date >= :from";
$params[':from'] = $filter_from;
}
if ($filter_to !== '') {
$where .= " AND i.invoice_date <= :to";
$params[':to'] = $filter_to;
}
try {
$sql = "SELECT i.*, c.name AS customer_name, c.customer_number,
COALESCE(i.is_storno, FALSE) AS is_storno,
i.storno_of,
storno_child.invoice_number AS storno_child_number,
storno_child.id AS storno_child_id
FROM invoices i
JOIN customers c ON c.id = i.customer_id
LEFT JOIN invoices storno_child ON storno_child.storno_of = i.id
$where ORDER BY i.invoice_date DESC, i.id DESC";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
} catch (\PDOException $e) {
// is_storno/storno_of noch nicht migriert — Fallback
$sql = "SELECT i.*, c.name AS customer_name, c.customer_number,
FALSE AS is_storno, NULL AS storno_of,
NULL AS storno_child_number, NULL AS storno_child_id
FROM invoices i
JOIN customers c ON c.id = i.customer_id
$where ORDER BY i.invoice_date DESC, i.id DESC";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
}
$invoices = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Verknüpfte Journal-Einträge laden (nur wenn Spalte existiert)
$journal_linked = [];
try {
$stmt_jl = $pdo->query("SELECT invoice_id, id FROM journal_entries WHERE invoice_id IS NOT NULL");
foreach ($stmt_jl->fetchAll(PDO::FETCH_ASSOC) as $jl) {
$journal_linked[(int)$jl['invoice_id']] = (int)$jl['id'];
}
} catch (PDOException $e) {
// Spalte invoice_id existiert noch nicht - ignorieren
}
// Mahnungen pro Rechnung laden
$mahnungen_count = [];
try {
$stmt_m = $pdo->query("SELECT invoice_id, COUNT(*) AS cnt, MAX(level) AS max_level FROM mahnungen GROUP BY invoice_id");
foreach ($stmt_m->fetchAll(PDO::FETCH_ASSOC) as $m) {
$mahnungen_count[(int)$m['invoice_id']] = ['cnt' => $m['cnt'], 'level' => $m['max_level']];
}
} catch (PDOException $e) {
// Tabelle noch nicht migriert
}
?>
Rechnungen
= htmlspecialchars($msg) ?>
| Datum |
Nr. |
Kunde |
Betrag (brutto) |
Status |
Aktion |
>
| = htmlspecialchars(date('d.m.Y', strtotime($inv['invoice_date']))) ?> |
= htmlspecialchars($inv['invoice_number']) ?>
STORNO
storniert
|
= htmlspecialchars($inv['customer_name']) ?> |
= number_format($inv['total_gross'], 2, ',', '.') ?> € |
= $inv['paid'] ? 'bezahlt' : 'offen' ?>
M= $mahnung_info['level'] ?>
|
PDF
| bezahlt
| Mahnung
| Journal
| Storno
|
|
|
| Keine Rechnungen gefunden. |