505 lines
No EOL
7.9 KiB
HTML
505 lines
No EOL
7.9 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html lang="de">
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<title>
|
|
ING Finanzen
|
|
</title>
|
|
|
|
<link rel="stylesheet"
|
|
href="{{ url_for('static', filename='style.css') }}?v={{ css_version }}">
|
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="header">
|
|
|
|
|
|
<div class="header-left">
|
|
|
|
<img class="logo-ing"
|
|
src="{{ url_for('static', filename='logo_ing.png') }}">
|
|
|
|
<div>
|
|
|
|
<div class="title">
|
|
ING Finanzen
|
|
</div>
|
|
|
|
<div class="subtitle">
|
|
Kontobewegungen und Auswertungen
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<img class="logo-hintergasse"
|
|
src="{{ url_for('static', filename='logo_hintergasse.png') }}">
|
|
|
|
|
|
</div>
|
|
|
|
<div class="navbar">
|
|
|
|
<a href="/">Dashboard</a>
|
|
<a href="/categories">Kategorien</a>
|
|
<a href="/maintenance">Wartung</a>
|
|
<a href="/log">Log</a>
|
|
|
|
</div>
|
|
|
|
<div class="container">
|
|
|
|
<div class="cards">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="card">
|
|
|
|
<h2>
|
|
KW{{ week }}
|
|
</h2>
|
|
<p class="balance-label">
|
|
Kontostand
|
|
</p>
|
|
|
|
<p class="balance-value balance-{{ balance_color }}">
|
|
|
|
{% if balance is not none %}
|
|
|
|
{{ "%.2f"|format(balance) }} €
|
|
|
|
{% else %}
|
|
|
|
n/v
|
|
|
|
{% endif %}
|
|
|
|
</p>
|
|
<p>
|
|
Einnahmen:
|
|
<strong>
|
|
{{ "%.2f"|format(total_income) }} €
|
|
</strong>
|
|
</p>
|
|
|
|
<p>
|
|
Ausgaben:
|
|
<strong>
|
|
{{ "%.2f"|format(total_expenses) }} €
|
|
</strong>
|
|
</p>
|
|
|
|
<p>
|
|
Saldo:
|
|
<strong>
|
|
{{ "%.2f"|format(total_saldo) }} €
|
|
</strong>
|
|
</p>
|
|
|
|
</div>
|
|
<div class="card chart-card">
|
|
|
|
<h2>
|
|
Kontostandvergleich
|
|
</h2>
|
|
|
|
<canvas id="balanceChart"></canvas>
|
|
|
|
</div>
|
|
<div class="card">
|
|
|
|
<h2>
|
|
Transaktionen in dieser Woche
|
|
</h2>
|
|
|
|
{% if transactions %}
|
|
<div class="transaction-container">
|
|
<table class="transaction-table">
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>Datum</th>
|
|
<th>Name</th>
|
|
<th>Kategorie</th>
|
|
<th>Betrag</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
{% for t in transactions|reverse %}
|
|
|
|
<tr>
|
|
|
|
<td>
|
|
{{ t.date }}
|
|
</td>
|
|
|
|
<td>
|
|
{{ t.applicant_name }}
|
|
</td>
|
|
|
|
<td>
|
|
{{ t.category }}
|
|
</td>
|
|
|
|
<td class="{% if t.amount >= 0 %}amount-positive{% else %}amount-negative{% endif %}">
|
|
{{ "%.2f"|format(t.amount) }} €
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
|
|
</div>
|
|
{% else %}
|
|
|
|
<p>
|
|
Keine Transaktionen vorhanden.
|
|
</p>
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
<div class="card">
|
|
|
|
<h2>
|
|
Unbekannte Buchungen
|
|
</h2>
|
|
|
|
{% if unknown_transactions %}
|
|
|
|
<p>
|
|
{{ unknown_transactions|length }}
|
|
Buchungen offen
|
|
</p>
|
|
|
|
<table class="transaction-table">
|
|
|
|
{% for t in unknown_transactions %}
|
|
|
|
<tr>
|
|
|
|
<td>
|
|
{{ t.date }}
|
|
</td>
|
|
|
|
<td>
|
|
{{ t.applicant_name }}
|
|
</td>
|
|
|
|
<td>
|
|
{{ "%.2f"|format(t.amount) }} €
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
{% endfor %}
|
|
|
|
</table>
|
|
|
|
<br>
|
|
|
|
<a href="/categories">
|
|
|
|
<button type="button">
|
|
Kategorien öffnen
|
|
</button>
|
|
|
|
</a>
|
|
|
|
{% else %}
|
|
|
|
<p>
|
|
Keine unbekannten Buchungen.
|
|
</p>
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="footer">
|
|
|
|
|
|
Hintergasse © 2026
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
const currentDay = {{ current_day }};
|
|
const history = {{ balance_history|tojson }};
|
|
|
|
|
|
const currentPeriod = history.current || [];
|
|
|
|
const labels = currentPeriod.map(item => {
|
|
|
|
const today = new Date();
|
|
|
|
let month = today.getMonth();
|
|
let year = today.getFullYear();
|
|
|
|
if (today.getDate() < 15) {
|
|
|
|
month--;
|
|
|
|
if (month < 0) {
|
|
month = 11;
|
|
year--;
|
|
}
|
|
}
|
|
|
|
const startDate = new Date(
|
|
year,
|
|
month,
|
|
15
|
|
);
|
|
|
|
startDate.setDate(
|
|
startDate.getDate() + item.day - 1
|
|
);
|
|
|
|
return startDate.toLocaleDateString(
|
|
"de-DE",
|
|
{
|
|
day: "2-digit",
|
|
month: "2-digit"
|
|
}
|
|
);
|
|
|
|
});
|
|
|
|
function getSeries(periodName) {
|
|
|
|
const values = new Array(31).fill(null);
|
|
|
|
if (!history[periodName]) {
|
|
return values;
|
|
}
|
|
|
|
history[periodName].forEach(item => {
|
|
|
|
values[item.day - 1] = item.value;
|
|
|
|
});
|
|
|
|
if (periodName === "current") {
|
|
|
|
const lastDay = currentDay;
|
|
|
|
for (let i = lastDay; i < 31; i++) {
|
|
values[i] = null;
|
|
}
|
|
}
|
|
|
|
return values;
|
|
}
|
|
|
|
function getAverageSeries() {
|
|
|
|
const result = [];
|
|
|
|
for (let day = 0; day < 31; day++) {
|
|
|
|
const values = [];
|
|
|
|
[
|
|
"period_1",
|
|
"period_2",
|
|
"period_3",
|
|
"period_4"
|
|
].forEach(period => {
|
|
|
|
const series = getSeries(period);
|
|
|
|
if (
|
|
series[day] !== null &&
|
|
series[day] !== undefined
|
|
) {
|
|
values.push(series[day]);
|
|
}
|
|
|
|
});
|
|
|
|
if (values.length > 0) {
|
|
|
|
const avg =
|
|
values.reduce(
|
|
(a, b) => a + b,
|
|
0
|
|
) / values.length;
|
|
|
|
result.push(
|
|
Math.round(avg * 100) / 100
|
|
);
|
|
|
|
} else {
|
|
|
|
result.push(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
new Chart(
|
|
document.getElementById("balanceChart"),
|
|
{
|
|
type: "line",
|
|
|
|
data: {
|
|
|
|
labels: labels,
|
|
|
|
datasets: [
|
|
|
|
{
|
|
label: "Aktuell",
|
|
|
|
data: getSeries("current"),
|
|
|
|
tension: 0.3,
|
|
|
|
borderWidth: 5,
|
|
|
|
pointRadius: 3,
|
|
|
|
pointHoverRadius: 8,
|
|
|
|
spanGaps: false
|
|
},
|
|
|
|
{
|
|
label: "Durchschnitt",
|
|
|
|
data: getAverageSeries(),
|
|
|
|
tension: 0.3,
|
|
|
|
borderWidth: 3,
|
|
|
|
pointRadius: 0
|
|
},
|
|
|
|
{
|
|
label: "-1 Monat",
|
|
|
|
data: getSeries("period_1"),
|
|
|
|
tension: 0.3,
|
|
|
|
borderWidth: 1,
|
|
|
|
pointRadius: 0
|
|
},
|
|
|
|
{
|
|
label: "-2 Monate",
|
|
|
|
data: getSeries("period_2"),
|
|
|
|
tension: 0.3,
|
|
|
|
borderWidth: 1,
|
|
|
|
pointRadius: 0
|
|
},
|
|
|
|
{
|
|
label: "-3 Monate",
|
|
|
|
data: getSeries("period_3"),
|
|
|
|
tension: 0.3,
|
|
|
|
borderWidth: 1,
|
|
|
|
pointRadius: 0
|
|
},
|
|
|
|
{
|
|
label: "-4 Monate",
|
|
|
|
data: getSeries("period_4"),
|
|
|
|
tension: 0.3,
|
|
|
|
borderWidth: 1,
|
|
|
|
pointRadius: 0
|
|
}
|
|
|
|
]
|
|
},
|
|
|
|
options: {
|
|
|
|
responsive: true,
|
|
|
|
interaction: {
|
|
mode: "index",
|
|
intersect: false
|
|
},
|
|
|
|
plugins: {
|
|
|
|
legend: {
|
|
display: true
|
|
}
|
|
|
|
},
|
|
|
|
scales: {
|
|
|
|
x: {
|
|
title: {
|
|
display: true,
|
|
text: "Datum"
|
|
}
|
|
},
|
|
|
|
y: {
|
|
beginAtZero: false,
|
|
title: {
|
|
display: true,
|
|
text: "Kontostand (€)"
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
);
|
|
|
|
</script> |