Added support for Streamdeck Pedal and updated UI to better fit the Packed UI style

This commit is contained in:
2026-02-27 22:47:08 +01:00
committed by erik
parent 5a70f775f1
commit 93faae5cc8
1463 changed files with 306917 additions and 0 deletions

192
pirp/public/belegarchiv.php Normal file
View File

@@ -0,0 +1,192 @@
<?php
require_once __DIR__ . '/../src/config.php';
require_once __DIR__ . '/../src/auth.php';
require_once __DIR__ . '/../src/db.php';
require_once __DIR__ . '/../src/icons.php';
require_login();
$pdo = get_db();
$filter_type = $_GET['type'] ?? 'all'; // all | rechnung | ausgabe | mahnung
$filter_from = trim($_GET['from'] ?? '');
$filter_to = trim($_GET['to'] ?? '');
$filter_q = trim($_GET['q'] ?? '');
$invoice_id = isset($_GET['invoice_id']) ? (int)$_GET['invoice_id'] : 0;
$belege = [];
// ---- Rechnungs-PDFs ----
if ($filter_type === 'all' || $filter_type === 'rechnung') {
$base = "FROM invoices i JOIN customers c ON c.id = i.customer_id WHERE i.pdf_path IS NOT NULL";
$params = [];
if ($filter_from) { $base .= " AND i.invoice_date >= :from"; $params[':from'] = $filter_from; }
if ($filter_to) { $base .= " AND i.invoice_date <= :to"; $params[':to'] = $filter_to; }
if ($filter_q) { $base .= " AND (i.invoice_number ILIKE :q OR c.name ILIKE :q2)";
$params[':q'] = '%' . $filter_q . '%'; $params[':q2'] = '%' . $filter_q . '%'; }
try {
$sql = "SELECT i.id, i.invoice_date AS beleg_date, i.invoice_number AS beleg_ref,
c.name AS kunde, i.total_gross AS betrag, i.pdf_path,
'rechnung' AS beleg_type, COALESCE(i.is_storno, FALSE) AS is_storno $base";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
} catch (\PDOException $e) {
// is_storno Spalte noch nicht migriert — Fallback ohne die Spalte
$sql = "SELECT i.id, i.invoice_date AS beleg_date, i.invoice_number AS beleg_ref,
c.name AS kunde, i.total_gross AS betrag, i.pdf_path,
'rechnung' AS beleg_type, FALSE AS is_storno $base";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
}
$belege = array_merge($belege, $stmt->fetchAll(PDO::FETCH_ASSOC));
}
// ---- Ausgaben-Belege ----
if ($filter_type === 'all' || $filter_type === 'ausgabe') {
$sql = "SELECT e.id, e.expense_date AS beleg_date, e.description AS beleg_ref,
'' AS kunde, e.amount AS betrag, e.attachment_path AS pdf_path,
'ausgabe' AS beleg_type, FALSE AS is_storno
FROM expenses e
WHERE e.attachment_path IS NOT NULL";
$params = [];
if ($filter_from) { $sql .= " AND e.expense_date >= :from"; $params[':from'] = $filter_from; }
if ($filter_to) { $sql .= " AND e.expense_date <= :to"; $params[':to'] = $filter_to; }
if ($filter_q) { $sql .= " AND e.description ILIKE :q"; $params[':q'] = '%' . $filter_q . '%'; }
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$belege = array_merge($belege, $stmt->fetchAll(PDO::FETCH_ASSOC));
}
// ---- Mahnungen ----
$show_mahnungen = ($filter_type === 'all' || $filter_type === 'mahnung');
if ($show_mahnungen) {
$sql = "SELECT m.id, m.mahnung_date AS beleg_date,
'MAHNUNG L' || m.level || ' ' || i.invoice_number AS beleg_ref,
c.name AS kunde, i.total_gross + m.fee_amount AS betrag,
m.pdf_path, 'mahnung' AS beleg_type, FALSE AS is_storno,
m.invoice_id
FROM mahnungen m
JOIN invoices i ON i.id = m.invoice_id
JOIN customers c ON c.id = i.customer_id
WHERE m.pdf_path IS NOT NULL";
$params = [];
if ($invoice_id) { $sql .= " AND m.invoice_id = :iid"; $params[':iid'] = $invoice_id; }
if ($filter_from) { $sql .= " AND m.mahnung_date >= :from"; $params[':from'] = $filter_from; }
if ($filter_to) { $sql .= " AND m.mahnung_date <= :to"; $params[':to'] = $filter_to; }
if ($filter_q) { $sql .= " AND (i.invoice_number ILIKE :q OR c.name ILIKE :q2)";
$params[':q'] = '%' . $filter_q . '%'; $params[':q2'] = '%' . $filter_q . '%'; }
try {
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$belege = array_merge($belege, $stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (\PDOException $e) {
// Tabelle noch nicht migriert
}
}
// Sortieren: neueste zuerst
usort($belege, fn($a, $b) => strcmp($b['beleg_date'], $a['beleg_date']));
$type_labels = ['rechnung' => 'Rechnung', 'ausgabe' => 'Ausgabe', 'mahnung' => 'Mahnung'];
$type_colors = ['rechnung' => 'var(--accent)', 'ausgabe' => 'var(--info)', 'mahnung' => 'var(--warning)'];
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Belegarchiv</title>
<link rel="stylesheet" href="assets/style.css">
</head>
<body>
<header>
<h1>PIRP</h1>
<nav>
<a href="<?= url_for('index.php') ?>"><?= icon_dashboard() ?>Dashboard</a>
<a href="<?= url_for('invoices.php') ?>"><?= icon_invoices() ?>Rechnungen</a>
<a href="<?= url_for('customers.php') ?>"><?= icon_customers() ?>Kunden</a>
<a href="<?= url_for('expenses.php') ?>"><?= icon_expenses() ?>Ausgaben</a>
<a href="<?= url_for('belegarchiv.php') ?>" class="active"><?= icon_archive() ?>Belege</a>
<a href="<?= url_for('journal.php') ?>"><?= icon_journal() ?>Journal</a>
<a href="<?= url_for('euer.php') ?>"><?= icon_euer() ?>EÜR</a>
<a href="<?= url_for('settings.php') ?>"><?= icon_settings() ?>Einstellungen</a>
<a href="<?= url_for('logout.php') ?>"><?= icon_logout() ?>Logout (<?= htmlspecialchars($_SESSION['username'] ?? '') ?>)</a>
<span class="cmd-k-hint" onclick="document.dispatchEvent(new KeyboardEvent('keydown',{key:'k',ctrlKey:true}))"><kbd>Ctrl+K</kbd></span>
</nav>
</header>
<main>
<form method="get" class="filters">
<label>Typ:
<select name="type">
<option value="all" <?= $filter_type === 'all' ? 'selected' : '' ?>>Alle</option>
<option value="rechnung" <?= $filter_type === 'rechnung' ? 'selected' : '' ?>>Rechnungen</option>
<option value="ausgabe" <?= $filter_type === 'ausgabe' ? 'selected' : '' ?>>Ausgaben</option>
<option value="mahnung" <?= $filter_type === 'mahnung' ? 'selected' : '' ?>>Mahnungen</option>
</select>
</label>
<label>Suche:
<input type="text" name="q" value="<?= htmlspecialchars($filter_q) ?>" placeholder="Nr., Beschreibung, Kunde...">
</label>
<label>Von:
<input type="date" name="from" value="<?= htmlspecialchars($filter_from) ?>">
</label>
<label>Bis:
<input type="date" name="to" value="<?= htmlspecialchars($filter_to) ?>">
</label>
<button type="submit">Filtern</button>
<a href="<?= url_for('belegarchiv.php') ?>">Zurücksetzen</a>
</form>
<section>
<h2>Belegarchiv
<span style="font-weight:normal;font-size:12px;color:var(--text-muted);"><?= count($belege) ?> Dokument(e)</span>
</h2>
<?php if (empty($belege)): ?>
<p style="color:var(--text-muted);">Keine Belege gefunden.</p>
<?php else: ?>
<table class="list">
<thead>
<tr>
<th>Datum</th>
<th>Typ</th>
<th>Referenz / Beschreibung</th>
<th>Kunde</th>
<th style="text-align:right;">Betrag</th>
<th>PDF</th>
</tr>
</thead>
<tbody>
<?php foreach ($belege as $b): ?>
<tr>
<td><?= date('d.m.Y', strtotime($b['beleg_date'])) ?></td>
<td>
<span style="font-size:10px;color:<?= $type_colors[$b['beleg_type']] ?? 'var(--text)' ?>;">
<?= $type_labels[$b['beleg_type']] ?? $b['beleg_type'] ?>
<?php if (!empty($b['is_storno'])): ?>
<span style="color:var(--error);"> · STORNO</span>
<?php endif; ?>
</span>
</td>
<td><?= htmlspecialchars($b['beleg_ref']) ?></td>
<td style="color:var(--text-muted);"><?= htmlspecialchars($b['kunde']) ?></td>
<td style="text-align:right;font-family:var(--font-mono);font-size:12px;">
<?= number_format((float)$b['betrag'], 2, ',', '.') ?> €
</td>
<td>
<?php if ($b['beleg_type'] === 'rechnung'): ?>
<a href="<?= url_for('invoice_pdf.php?id=' . $b['id']) ?>" target="_blank">PDF</a>
<?php elseif ($b['beleg_type'] === 'ausgabe'): ?>
<a href="<?= url_for('expense_file.php?id=' . $b['id']) ?>" target="_blank">PDF</a>
<?php elseif ($b['beleg_type'] === 'mahnung'): ?>
<a href="<?= url_for('mahnung_pdf.php?id=' . $b['id']) ?>" target="_blank">PDF</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</section>
</main>
<script src="assets/command-palette.js"></script>
</body>
</html>