Files
game1.shadow-land.de/www/public/finances.php
madgerm 12ddf5a185 feat(phase2): aircraft market, fleet management, finances, loans
- market.php: Buy new aircraft (6 types: Dash8 to A380)
- aircraft.php: Fleet management, crew assignment, route planning
- finances.php: Account balance, transactions, loans
- Database.php: Extended with loan/transaction/aircraft methods
- schema.sql: Aircraft types table, 10M starting balance, INSERT OR IGNORE
- dashboard.php: Updated with fleet/financial overview
- Fixed: duplicate function declarations in Database.php
- Fixed: initializeSchema() with idempotent error handling
2026-04-24 17:27:02 +02:00

440 lines
20 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Airline Tycoon - Finanz-Übersicht
* Zeigt alle Finanzen, Transaktionen, Kredite und Bilanzen
*/
require_once __DIR__ . '/../src/bootstrap.php';
// Auth Check
if (!Session::isLoggedIn()) {
header('Location: login.php');
exit;
}
$userId = Session::getUserId();
$user = $db->getUserById($userId);
$config = $db->getConfig();
$csrfToken = Session::generateCsrfToken();
// Kredite holen
$loans = $db->getUserLoans($userId);
$totalDebt = $db->getTotalDebt($userId);
$totalDebtWithInterest = $db->getTotalDebtWithInterest($userId);
// Transaktionen holen
$transactions = $db->getUserTransactions($userId, 50);
// Heutige Statistik
$today = date('Y-m-d');
$todayStats = $db->getTransactionSummary($userId, $today, $today);
// Letzte 7 Tage
$weekAgo = date('Y-m-d', strtotime('-7 days'));
$weekStats = $db->getTransactionSummary($userId, $weekAgo, $today);
// Letzte 30 Tage
$monthAgo = date('Y-m-d', strtotime('-30 days'));
$monthStats = $db->getTransactionSummary($userId, $monthAgo, $today);
// Wartungshistorie
$maintenanceHistory = $db->getMaintenanceHistory($userId, 10);
// Net Worth (Balance - Schulden)
$netWorth = $user['balance'] - $totalDebtWithInterest;
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Finanzen - <?= htmlspecialchars($user['airline_name']) ?> - <?= $config['app']['name'] ?></title>
<link rel="stylesheet" href="<?= $basePath ?>assets/css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Bangers&family=Patrick+Hand&family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
</head>
<body data-theme="<?= $theme ?? 'light' ?>">
<!-- Navbar -->
<nav class="navbar">
<div class="navbar-brand">
<a href="<?= $basePath ?>dashboard.php" class="navbar-logo">✈️ <?= $config['app']['name'] ?></a>
</div>
<button class="navbar-toggle" aria-label="Menü">☰</button>
<div class="navbar-menu">
<a href="<?= $basePath ?>dashboard.php" class="navbar-item">Dashboard</a>
<a href="<?= $basePath ?>airports.php" class="navbar-item">Flughäfen</a>
<a href="<?= $basePath ?>aircraft.php" class="navbar-item">Flotte</a>
<a href="<?= $basePath ?>finances.php" class="navbar-item active">Finanzen</a>
<a href="<?= $basePath ?>market.php" class="navbar-item">Markt</a>
<button class="theme-toggle" id="themeToggle" title="Theme wechseln">🌙</button>
</div>
</nav>
<!-- Main Content -->
<main class="container">
<!-- Header -->
<section class="hero hero-sm">
<div class="hero-content">
<h1 class="hero-title">💰 Finanzen</h1>
<p class="hero-subtitle">Deine Einnahmen, Ausgaben und Kredite im Überblick</p>
</div>
</section>
<!-- Kontostand & Net Worth -->
<div class="stats-grid mt-lg">
<div class="stat-card">
<div class="stat-icon">💵</div>
<div class="stat-value <?= $user['balance'] >= 0 ? 'text-success' : 'text-danger' ?>">
<?= number_format($user['balance'], 0, ',', '.') ?> €
</div>
<div class="stat-label">Kontostand</div>
</div>
<div class="stat-card">
<div class="stat-icon">📊</div>
<div class="stat-value <?= $netWorth >= 0 ? 'text-success' : 'text-danger' ?>">
<?= number_format($netWorth, 0, ',', '.') ?> €
</div>
<div class="stat-label">Net Worth</div>
</div>
<div class="stat-card">
<div class="stat-icon">🏦</div>
<div class="stat-value <?= $totalDebt > 0 ? 'text-warning' : 'text-success' ?>">
<?= number_format($totalDebtWithInterest, 0, ',', '.') ?> €
</div>
<div class="stat-label">Kredit-Schuld</div>
</div>
<div class="stat-card">
<div class="stat-icon">📈</div>
<div class="stat-value">
<?= $config['loans']['interest_rate'] * 100 ?>%
</div>
<div class="stat-label">Kredit-Zins/Ticket</div>
</div>
</div>
<!-- Zeitraum-Statistiken -->
<section class="panel mt-xl">
<h2 class="panel-title">📅 Bilanz nach Zeitraum</h2>
<div class="period-stats mt-md">
<div class="period-card">
<h3>Heute</h3>
<div class="period-amounts">
<div class="amount-row">
<span>Einnahmen:</span>
<span class="text-success">+<?= number_format($todayStats['total_income'] ?? 0, 2, ',', '.') ?> €</span>
</div>
<div class="amount-row">
<span>Ausgaben:</span>
<span class="text-danger">-<?= number_format($todayStats['total_expenses'] ?? 0, 2, ',', '.') ?> €</span>
</div>
<div class="amount-row total">
<span>Saldo:</span>
<span class="<?= ($todayStats['total_income'] - $todayStats['total_expenses']) >= 0 ? 'text-success' : 'text-danger' ?>">
<?= number_format(($todayStats['total_income'] ?? 0) - ($todayStats['total_expenses'] ?? 0), 2, ',', '.') ?> €
</span>
</div>
</div>
</div>
<div class="period-card">
<h3>Letzte 7 Tage</h3>
<div class="period-amounts">
<div class="amount-row">
<span>Einnahmen:</span>
<span class="text-success">+<?= number_format($weekStats['total_income'] ?? 0, 2, ',', '.') ?> €</span>
</div>
<div class="amount-row">
<span>Ausgaben:</span>
<span class="text-danger">-<?= number_format($weekStats['total_expenses'] ?? 0, 2, ',', '.') ?> €</span>
</div>
<div class="amount-row total">
<span>Saldo:</span>
<span class="<?= ($weekStats['total_income'] - $weekStats['total_expenses']) >= 0 ? 'text-success' : 'text-danger' ?>">
<?= number_format(($weekStats['total_income'] ?? 0) - ($weekStats['total_expenses'] ?? 0), 2, ',', '.') ?> €
</span>
</div>
</div>
</div>
<div class="period-card">
<h3>Letzte 30 Tage</h3>
<div class="period-amounts">
<div class="amount-row">
<span>Einnahmen:</span>
<span class="text-success">+<?= number_format($monthStats['total_income'] ?? 0, 2, ',', '.') ?> €</span>
</div>
<div class="amount-row">
<span>Ausgaben:</span>
<span class="text-danger">-<?= number_format($monthStats['total_expenses'] ?? 0, 2, ',', '.') ?> €</span>
</div>
<div class="amount-row total">
<span>Saldo:</span>
<span class="<?= ($monthStats['total_income'] - $monthStats['total_expenses']) >= 0 ? 'text-success' : 'text-danger' ?>">
<?= number_format(($monthStats['total_income'] ?? 0) - ($monthStats['total_expenses'] ?? 0), 2, ',', '.') ?> €
</span>
</div>
</div>
</div>
</div>
</section>
<!-- Kredite -->
<section class="panel mt-xl">
<div class="panel-header">
<h2 class="panel-title">🏦 Kredite</h2>
<button class="btn btn-primary" onclick="openModal('takeLoanModal')">
Kredit aufnehmen
</button>
</div>
<?php if (empty($loans)): ?>
<div class="empty-state">
<div class="empty-icon">🏦</div>
<h3>Keine Kredite</h3>
<p>Du hast keine Kredite offen. Nimm einen Kredit auf, um dein Geschäft zu finanzieren!</p>
</div>
<?php else: ?>
<div class="table-container mt-md">
<table class="table">
<thead>
<tr>
<th>Datum</th>
<th>Originalbetrag</th>
<th>Aktueller Betrag</th>
<th>Tageszins</th>
<th>Tage offen</th>
<th>Gesamtzins</th>
<th>Aktion</th>
</tr>
</thead>
<tbody>
<?php foreach ($loans as $loan):
$totalInterest = $loan['daily_interest'] * $loan['days_outstanding'];
$totalOwed = $loan['current_amount'] + $totalInterest;
?>
<tr>
<td><?= date('d.m.Y', strtotime($loan['created_at'])) ?></td>
<td><?= number_format($loan['principal'], 2, ',', '.') ?> €</td>
<td><?= number_format($loan['current_amount'], 2, ',', '.') ?> €</td>
<td><?= number_format($loan['daily_interest'], 2, ',', '.') ?> €</td>
<td><?= $loan['days_outstanding'] ?></td>
<td><?= number_format($totalInterest, 2, ',', '.') ?> €</td>
<td>
<button class="btn btn-sm btn-warning"
onclick="repayLoan(<?= $loan['id'] ?>, <?= $totalOwed ?>)">
💵 Zurückzahlen
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
<div class="loan-info panel mt-lg">
<h3>📖 Kredit-Informationen</h3>
<ul>
<li>Maximaler Kreditbetrag: <?= number_format($config['loans']['max_amount'], 0, ',', '.') ?> €</li>
<li>Zinssatz: <?= $config['loans']['interest_rate'] * 100 ?>% pro Spieltag</li>
<li>Mindestkreditbetrag: <?= number_format($config['loans']['min_amount'], 0, ',', '.') ?> €</li>
</ul>
</div>
</section>
<!-- Letzte Transaktionen -->
<section class="panel mt-xl">
<h2 class="panel-title">📜 Letzte Transaktionen</h2>
<?php if (empty($transactions)): ?>
<div class="empty-state">
<div class="empty-icon">📋</div>
<h3>Keine Transaktionen</h3>
<p>Es gibt noch keine Transaktionen.</p>
</div>
<?php else: ?>
<div class="table-container mt-md">
<table class="table">
<thead>
<tr>
<th>Datum</th>
<th>Typ</th>
<th>Beschreibung</th>
<th>Betrag</th>
<th>Saldo</th>
</tr>
</thead>
<tbody>
<?php foreach ($transactions as $tx): ?>
<tr>
<td><?= date('d.m.Y H:i', strtotime($tx['created_at'])) ?></td>
<td>
<?php
$typeColors = [
'flight' => 'badge-primary',
'fuel' => 'badge-warning',
'maintenance' => 'badge-danger',
'aircraft_purchase' => 'badge-info',
'loan' => 'badge-secondary',
'loan_repayment' => 'badge-warning'
];
$badgeClass = $typeColors[$tx['type']] ?? 'badge-secondary';
?>
<span class="badge <?= $badgeClass ?>"><?= htmlspecialchars($tx['type']) ?></span>
</td>
<td><?= htmlspecialchars($tx['description']) ?></td>
<td class="<?= $tx['amount'] >= 0 ? 'text-success' : 'text-danger' ?>">
<?= number_format($tx['amount'], 2, ',', '.') ?> €
</td>
<td><?= number_format($tx['balance_after'], 2, ',', '.') ?> €</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</section>
<!-- Wartungshistorie -->
<?php if (!empty($maintenanceHistory)): ?>
<section class="panel mt-xl">
<h2 class="panel-title">🔧 Wartungshistorie</h2>
<div class="table-container mt-md">
<table class="table">
<thead>
<tr>
<th>Datum</th>
<th>Flugzeug</th>
<th>Typ</th>
<th>Zustand vorher</th>
<th>Zustand nachher</th>
<th>Kosten</th>
</tr>
</thead>
<tbody>
<?php foreach ($maintenanceHistory as $m): ?>
<tr>
<td><?= date('d.m.Y', strtotime($m['created_at'])) ?></td>
<td><?= htmlspecialchars($m['aircraft_name']) ?></td>
<td><span class="badge"><?= htmlspecialchars($m['maintenance_type']) ?></span></td>
<td><?= number_format($m['condition_before'], 1, ',', '.') ?>%</td>
<td><?= number_format($m['condition_after'], 1, ',', '.') ?>%</td>
<td class="text-danger">-<?= number_format($m['cost'], 2, ',', '.') ?> €</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</section>
<?php endif; ?>
</main>
<!-- Kredit aufnehmen Modal -->
<div class="modal-overlay" id="takeLoanModal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">🏦 Kredit aufnehmen</h3>
<button class="modal-close" onclick="closeModal('takeLoanModal')">×</button>
</div>
<form action="api/game.php" method="POST" data-ajax>
<input type="hidden" name="action" value="take_loan">
<input type="hidden" name="csrf_token" value="<?= $csrfToken ?>">
<div class="modal-body">
<div class="form-group">
<label class="form-label">Kreditbetrag (€)</label>
<input type="number" name="amount" class="form-input"
min="<?= $config['loans']['min_amount'] ?>"
max="<?= $config['loans']['max_amount'] - $totalDebt ?>"
step="10000"
placeholder="z.B. 1000000" required>
<small class="form-hint">
Min: <?= number_format($config['loans']['min_amount'], 0, ',', '.') ?> € |
Max: <?= number_format($config['loans']['max_amount'] - $totalDebt, 0, ',', '.') ?> € verfügbar
</small>
</div>
<div class="alert alert-info mt-md">
<p><strong>Zinssatz:</strong> <?= $config['loans']['interest_rate'] * 100 ?>% pro Spieltag</p>
<p><strong>Tageszins für max. Kredit:</strong> <?= number_format(($config['loans']['max_amount'] - $totalDebt) * $config['loans']['interest_rate'], 2, ',', '.') ?> €</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeModal('takeLoanModal')">Abbrechen</button>
<button type="submit" class="btn btn-primary">Kredit aufnehmen</button>
</div>
</form>
</div>
</div>
<!-- Kredit zurückzahlen Modal -->
<div class="modal-overlay" id="repayLoanModal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">💵 Kredit zurückzahlen</h3>
<button class="modal-close" onclick="closeModal('repayLoanModal')">×</button>
</div>
<form action="api/game.php" method="POST" data-ajax>
<input type="hidden" name="action" value="repay_loan">
<input type="hidden" name="csrf_token" value="<?= $csrfToken ?>">
<input type="hidden" name="loan_id" id="repayLoanId">
<div class="modal-body">
<p>Gesamtbetrag inkl. Zinsen: <strong id="repayTotalAmount"></strong></p>
<div class="form-group mt-md">
<label class="form-label">Zurückzahlungsbetrag (€)</label>
<input type="number" name="amount" class="form-input"
min="100" step="1000"
id="repayAmountInput" required>
<small class="form-hint">Du kannst auch nur einen Teil zurückzahlen.</small>
</div>
<div class="alert alert-warning mt-md">
<p>💡 Du kannst den Kredit jederzeit (teilweise oder vollständig) zurückzahlen.</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="closeModal('repayLoanModal')">Abbrechen</button>
<button type="submit" class="btn btn-warning">Zurückzahlen</button>
</div>
</form>
</div>
</div>
<!-- Toast Container -->
<div id="toastContainer" class="toast-container"></div>
<script src="<?= $basePath ?>assets/js/main.js"></script>
<script>
let currentLoanId = null;
let currentTotalOwed = 0;
function repayLoan(loanId, totalOwed) {
currentLoanId = loanId;
currentTotalOwed = totalOwed;
document.getElementById('repayLoanId').value = loanId;
document.getElementById('repayTotalAmount').textContent =
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(totalOwed);
document.getElementById('repayAmountInput').max = totalOwed;
document.getElementById('repayAmountInput').value = totalOwed;
openModal('repayLoanModal');
}
// Erfolg-Callbacks
window.loanSuccess = function(data) {
showToast('Kredit über ' + formatMoney(data.amount) + ' aufgenommen!', 'success');
setTimeout(() => location.reload(), 1500);
};
window.repaySuccess = function(data) {
showToast('Kredit zurückgezahlt: ' + formatMoney(data.repaid), 'success');
setTimeout(() => location.reload(), 1500);
};
function formatMoney(amount) {
return new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(amount);
}
</script>
</body>
</html>