Feature: Zahlart-Filter im Personenreport (Issue #11)

Ergänzt rep-person.php um eine zweite Filtertabelle für Zahlweisen
neben der Kategorien-Auswahl; die Summen werden entsprechend beider
Filter berechnet. Der Link zum Dashboard gibt die gewählten Zahlweisen
als Vorauswahl weiter, analog zur bestehenden Kategorien-Vorauswahl.
This commit is contained in:
fds2610-bot 2026-07-26 14:13:10 +02:00
parent 74629649f2
commit 803c1e5867
5 changed files with 110 additions and 9 deletions

View file

@ -97,10 +97,20 @@ h1 {
outline: none; outline: none;
} }
#categories_rep_person { .category-checkbox-list {
font-size: 12px; font-size: 12px;
} }
.filter-columns {
display: flex;
flex-wrap: wrap;
gap: 40px;
}
.filter-column {
min-width: 160px;
}
.btn-submit { .btn-submit {
display: inline-block; display: inline-block;
background: var(--primary-color); background: var(--primary-color);

View file

@ -94,6 +94,7 @@ foreach ($entries as $entry) {
$presetZahler = isset($_GET['zahler']) ? $_GET['zahler'] : ''; $presetZahler = isset($_GET['zahler']) ? $_GET['zahler'] : '';
$presetKategorie = isset($_GET['kategorie']) ? $_GET['kategorie'] : ''; $presetKategorie = isset($_GET['kategorie']) ? $_GET['kategorie'] : '';
$presetKategorien = isset($_GET['kategorien']) && is_array($_GET['kategorien']) ? $_GET['kategorien'] : []; $presetKategorien = isset($_GET['kategorien']) && is_array($_GET['kategorien']) ? $_GET['kategorien'] : [];
$presetZahlweisen = isset($_GET['zahlweisen']) && is_array($_GET['zahlweisen']) ? $_GET['zahlweisen'] : [];
$filterZahler = array_keys($filterZahler); $filterZahler = array_keys($filterZahler);
$filterPersonen = array_keys($filterPersonen); $filterPersonen = array_keys($filterPersonen);
@ -240,6 +241,8 @@ document.querySelector('.hamburger').addEventListener('click', function() {
const sumValue = document.getElementById('sum-value'); const sumValue = document.getElementById('sum-value');
// Mehrfach-Kategorie-Vorauswahl, z. B. per Link aus dem Personenreport (Kategorie-Select kann nur einen Wert anzeigen) // Mehrfach-Kategorie-Vorauswahl, z. B. per Link aus dem Personenreport (Kategorie-Select kann nur einen Wert anzeigen)
const presetKategorien = <?= json_encode(array_map('strtolower', $presetKategorien)) ?>; const presetKategorien = <?= json_encode(array_map('strtolower', $presetKategorien)) ?>;
// Mehrfach-Zahlweise-Vorauswahl, z. B. per Link aus dem Personenreport (Zahlweise-Select kann nur einen Wert anzeigen)
const presetZahlweisen = <?= json_encode(array_map('strtolower', $presetZahlweisen)) ?>;
function applyFilters() { function applyFilters() {
const activeFilters = Array.from(filters) const activeFilters = Array.from(filters)
@ -253,7 +256,8 @@ document.querySelector('.hamburger').addEventListener('click', function() {
const cell = cells[f.col]; const cell = cells[f.col];
if (!cell) return true; if (!cell) return true;
return cell.textContent.trim().toLowerCase().includes(f.value); return cell.textContent.trim().toLowerCase().includes(f.value);
}) && (presetKategorien.length === 0 || (cells[3] && presetKategorien.includes(cells[3].textContent.trim().toLowerCase()))); }) && (presetKategorien.length === 0 || (cells[3] && presetKategorien.includes(cells[3].textContent.trim().toLowerCase())))
&& (presetZahlweisen.length === 0 || (cells[4] && presetZahlweisen.includes(cells[4].textContent.trim().toLowerCase())));
row.style.display = visible ? '' : 'none'; row.style.display = visible ? '' : 'none';
if (visible) { if (visible) {
const amountCell = cells[6]; const amountCell = cells[6];

View file

@ -123,6 +123,23 @@ function fscash_resolve_selected_categories(array $allCategoryIds, $requestedCat
return $allCategoryIds; return $allCategoryIds;
} }
/**
* Ermittelt die im Personenreport ausgewählten Zahlweise-IDs: die per
* Request übergebenen, sofern vorhanden, sonst alle verfügbaren.
*
* @param int[] $allPaymentMethodIds Alle in der DB vorhandenen Zahlweise-IDs.
* @param mixed $requestedPaymentMethodIds Roher Wert aus $_GET['payment_methods'] (oder null, falls nicht gesetzt).
* @return array<int,mixed>
*/
function fscash_resolve_selected_payment_methods(array $allPaymentMethodIds, $requestedPaymentMethodIds): array
{
if (is_array($requestedPaymentMethodIds) && $requestedPaymentMethodIds !== []) {
return $requestedPaymentMethodIds;
}
return $allPaymentMethodIds;
}
/** /**
* Extrahiert den aktuellen Kurs aus einer Alpha-Vantage GLOBAL_QUOTE-Antwort. * Extrahiert den aktuellen Kurs aus einer Alpha-Vantage GLOBAL_QUOTE-Antwort.
* *

View file

@ -32,8 +32,18 @@ $selectedCategories = fscash_resolve_selected_categories(
$_GET['categories'] ?? null $_GET['categories'] ?? null
); );
// Zahlweisen aus der Datenbank abrufen
$paymentMethodStmt = $pdo->query("SELECT payment_method_id, name FROM payment_methods ORDER BY name");
$paymentMethods = $paymentMethodStmt->fetchAll();
// Daten abrufen für den ausgewählten Monat und die ausgewählten Kategorien // Standardmäßig alle Zahlweisen auswählen, falls keine Auswahl getroffen wurde
$selectedPaymentMethods = fscash_resolve_selected_payment_methods(
array_column($paymentMethods, 'payment_method_id'),
$_GET['payment_methods'] ?? null
);
// Daten abrufen für den ausgewählten Monat, die ausgewählten Kategorien und Zahlweisen
$sql = " $sql = "
SELECT SELECT
u.id AS user_id, u.id AS user_id,
@ -46,11 +56,12 @@ entries e ON e.user_id = u.id
AND MONTH(e.date) = ? AND MONTH(e.date) = ?
AND YEAR(e.date) = ? AND YEAR(e.date) = ?
AND e.category IN (" . implode(',', array_fill(0, count($selectedCategories), '?')) . ") AND e.category IN (" . implode(',', array_fill(0, count($selectedCategories), '?')) . ")
AND e.payment_method IN (" . implode(',', array_fill(0, count($selectedPaymentMethods), '?')) . ")
GROUP BY GROUP BY
u.id, u.username; u.id, u.username;
"; ";
$params = array_merge([$month, $year], $selectedCategories); $params = array_merge([$month, $year], $selectedCategories, $selectedPaymentMethods);
$stmt = $pdo->prepare($sql); $stmt = $pdo->prepare($sql);
$stmt->execute($params); $stmt->execute($params);
$entries = $stmt->fetchAll(); $entries = $stmt->fetchAll();
@ -62,6 +73,14 @@ foreach ($categories as $category) {
$selectedCategoryNames[] = $category['name']; $selectedCategoryNames[] = $category['name'];
} }
} }
// Namen der aktuell ausgewählten Zahlweisen ermitteln (für den Link zum Dashboard)
$selectedPaymentMethodNames = [];
foreach ($paymentMethods as $paymentMethod) {
if (in_array($paymentMethod['payment_method_id'], $selectedPaymentMethods)) {
$selectedPaymentMethodNames[] = $paymentMethod['name'];
}
}
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de"> <html lang="de">
@ -93,10 +112,13 @@ foreach ($categories as $category) {
<h2><?= strftime('%B %Y', mktime(0, 0, 0, $month, 1, $year)) ?></h2> <h2><?= strftime('%B %Y', mktime(0, 0, 0, $month, 1, $year)) ?></h2>
<!-- Multiselect für Kategorien --> <!-- Multiselect für Kategorien und Zahlweisen -->
<form method="get" action="rep-person.php" class="category-filter"> <form method="get" action="rep-person.php" class="category-filter">
<input type="hidden" name="year" value="<?= $year ?>"> <input type="hidden" name="year" value="<?= $year ?>">
<input type="hidden" name="month" value="<?= $month ?>"> <input type="hidden" name="month" value="<?= $month ?>">
<div class="filter-columns">
<div class="filter-column">
<label for="categories">Kategorien:</label> <label for="categories">Kategorien:</label>
<div class="category-checkbox-list" id="categories_rep_person"> <div class="category-checkbox-list" id="categories_rep_person">
@ -113,6 +135,27 @@ foreach ($categories as $category) {
</label><br/> </label><br/>
<?php endforeach; ?> <?php endforeach; ?>
<br/></div> <br/></div>
</div>
<div class="filter-column">
<label for="payment_methods">Zahlweisen:</label>
<div class="category-checkbox-list" id="payment_methods_rep_person">
<?php foreach ($paymentMethods as $paymentMethod): ?>
<label class="category-checkbox">
<input
type="checkbox"
name="payment_methods[]"
value="<?= $paymentMethod['payment_method_id'] ?>"
<?= in_array($paymentMethod['payment_method_id'], $selectedPaymentMethods) ? 'checked' : '' ?>
onchange="this.form.submit()"
>
<?= htmlspecialchars($paymentMethod['name']) ?>
</label><br/>
<?php endforeach; ?>
<br/></div>
</div>
</div>
<!-- button type="submit">Filtern</button --> <!-- button type="submit">Filtern</button -->
</form> </form>
@ -134,6 +177,7 @@ foreach ($categories as $category) {
'month' => $month, 'month' => $month,
'zahler' => $entry['username'] ?? '', 'zahler' => $entry['username'] ?? '',
'kategorien' => $selectedCategoryNames, 'kategorien' => $selectedCategoryNames,
'zahlweisen' => $selectedPaymentMethodNames,
]) ?>"> ]) ?>">
<?= htmlspecialchars(number_format($entry['gesamtbetrag'], 2, ',', '.')) ?> <?= htmlspecialchars(number_format($entry['gesamtbetrag'], 2, ',', '.')) ?>
</a> </a>

View file

@ -187,6 +187,32 @@ final class FscashTest extends TestCase
); );
} }
// --- fscash_resolve_selected_payment_methods --------------------------
public function testResolveSelectedPaymentMethodsMitAuswahl(): void
{
$this->assertSame(
[2, 3],
fscash_resolve_selected_payment_methods([1, 2, 3, 4], [2, 3])
);
}
public function testResolveSelectedPaymentMethodsOhneAuswahlLiefertAlle(): void
{
$this->assertSame(
[1, 2, 3, 4],
fscash_resolve_selected_payment_methods([1, 2, 3, 4], null)
);
}
public function testResolveSelectedPaymentMethodsBeiLeeremArrayLiefertAlle(): void
{
$this->assertSame(
[1, 2, 3, 4],
fscash_resolve_selected_payment_methods([1, 2, 3, 4], [])
);
}
// --- fscash_extract_quote_price -------------------------------------- // --- fscash_extract_quote_price --------------------------------------
public function testExtractQuotePriceLiestPreisAus(): void public function testExtractQuotePriceLiestPreisAus(): void