Boersenchecker
This commit is contained in:
513
modules/boersenchecker/partials/dashboard.php
Normal file
513
modules/boersenchecker/partials/dashboard.php
Normal file
@@ -0,0 +1,513 @@
|
||||
<?php $ownerQuery = $isAdmin ? '&owner_sub=' . urlencode((string) $ownerSub) : ''; ?>
|
||||
<?= module_shell_header('boersenchecker', [
|
||||
'title' => 'Depotverwaltung',
|
||||
]) ?>
|
||||
<div class="bc-page">
|
||||
<?php if ($error): ?>
|
||||
<section class="section-box"><div class="bc-alert bc-alert--error"><?= e($error) ?></div></section>
|
||||
<?php elseif ($notice): ?>
|
||||
<section class="section-box"><div class="bc-alert bc-alert--success"><?= e($notice) ?></div></section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($isAdmin): ?>
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Benutzer-Scope</h2>
|
||||
<p>Depots anderer Benutzer sind nur fuer `appadmin` sichtbar und bearbeitbar.</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="get" action="/apps/boersenchecker" style="margin-top:16px; display:flex; gap:10px; flex-wrap:wrap; align-items:end;">
|
||||
<input type="hidden" name="view" value="depotverwaltung">
|
||||
<label class="setup-field muted" style="margin:0; min-width:260px;">
|
||||
<span>Depots von Benutzer</span>
|
||||
<select name="owner_sub">
|
||||
<?php foreach ($availableOwners as $owner): ?>
|
||||
<option value="<?= e((string) $owner['sub']) ?>" <?= (string) $ownerSub === (string) $owner['sub'] ? 'selected' : '' ?>>
|
||||
<?= e((string) $owner['label']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<button class="bc-button bc-button--primary" type="submit">Anzeigen</button>
|
||||
</form>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="bc-card-grid">
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title"><?= $editPortfolio ? 'Depot bearbeiten' : 'Neues Depot' ?></h2>
|
||||
<p>Stammdaten und Berichtswahrung fuer ein Depot pflegen.</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" style="margin-top:16px; display:grid; gap:12px;">
|
||||
<input type="hidden" name="action" value="save_portfolio">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<input type="hidden" name="portfolio_id" value="<?= e((string) ($editPortfolio['id'] ?? '0')) ?>">
|
||||
<label class="setup-field muted">
|
||||
<span>Depotname</span>
|
||||
<input type="text" name="portfolio_name" value="<?= e((string) ($editPortfolio['name'] ?? '')) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Berichtswahrung</span>
|
||||
<input type="text" name="portfolio_base_currency" value="<?= e((string) ($editPortfolio['base_currency'] ?? $defaultReportCurrency)) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Notizen</span>
|
||||
<textarea name="portfolio_notes" rows="3"><?= e((string) ($editPortfolio['notes'] ?? '')) ?></textarea>
|
||||
</label>
|
||||
<div class="bc-actions">
|
||||
<button class="bc-button bc-button--primary" type="submit">Depot speichern</button>
|
||||
<?php if ($editPortfolio): ?>
|
||||
<a class="bc-button bc-button--secondary" href="/apps/boersenchecker?view=depotverwaltung<?= e($ownerQuery) ?>">Abbrechen</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">API / FX</h2>
|
||||
<p>Kurs- und Waehrungsdaten zentral aktualisieren.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="muted" style="margin-top:16px;">
|
||||
Die Umrechnung liest gespeicherte FX-Daten zentral aus dem Modul fx-rates. Eine Aktualisierung wird nur manuell
|
||||
angestossen und respektiert die dortige Max-Age- und Reuse-Logik.
|
||||
</p>
|
||||
<p class="muted" style="margin-top:12px;">
|
||||
Aktienkurse werden ueber Alpha Vantage anhand des hinterlegten Symbols abgerufen. Die ISIN bleibt als Stammdatum erhalten.
|
||||
</p>
|
||||
<div class="bc-actions" style="margin-top:16px;">
|
||||
<form method="post">
|
||||
<input type="hidden" name="action" value="refresh_fx">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<button class="bc-button bc-button--primary" type="submit">FX-Daten aktualisieren</button>
|
||||
</form>
|
||||
<form method="post">
|
||||
<input type="hidden" name="action" value="refresh_market_data_all">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<button class="bc-button bc-button--secondary" type="submit">Alle API-Kurse abrufen</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="muted" style="margin-top:12px;">
|
||||
Alpha Vantage Mindestabstand: <?= e((string) $marketDataMinIntervalMinutes) ?> Min.
|
||||
</div>
|
||||
<div class="muted" style="margin-top:6px;">
|
||||
API-Key und Timeout fuer Aktienkurse werden ueber <a href="/apps/boersenchecker?view=setup">dieses Modul-Setup</a> gepflegt.
|
||||
</div>
|
||||
<div class="muted" style="margin-top:6px;">
|
||||
FX-Provider, API-Key und Waehrungskatalog werden im Modul <a href="/apps/fx-rates">fx-rates</a> gepflegt.
|
||||
</div>
|
||||
<div class="muted" style="margin-top:12px;">
|
||||
Standard-Berichtswahrung: <?= e($defaultReportCurrency) ?> · Max. Alter: <?= e((string) $fxMaxAgeHours) ?>h
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title"><?= $editPosition ? 'Position bearbeiten' : 'Neue Position' ?></h2>
|
||||
<p>Aktienpositionen fuer ein Depot mit Kaufdaten und Kurswaehrung verwalten.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($portfolios === []): ?>
|
||||
<div class="muted" style="margin-top:16px;">Bitte zuerst ein Depot anlegen.</div>
|
||||
<?php else: ?>
|
||||
<form method="post" style="margin-top:16px; display:grid; gap:12px;">
|
||||
<input type="hidden" name="action" value="save_position">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<input type="hidden" name="position_id" value="<?= e((string) ($editPosition['id'] ?? '0')) ?>">
|
||||
<input type="hidden" name="instrument_id" value="<?= e((string) ($editPosition['instrument_id'] ?? '0')) ?>">
|
||||
<label class="setup-field muted">
|
||||
<span>Depot</span>
|
||||
<select name="portfolio_id" required>
|
||||
<option value="">Bitte waehlen</option>
|
||||
<?php foreach ($portfolios as $portfolio): ?>
|
||||
<option value="<?= e((string) $portfolio['id']) ?>" <?= (string) ($editPosition['portfolio_id'] ?? '') === (string) $portfolio['id'] ? 'selected' : '' ?>>
|
||||
<?= e((string) $portfolio['name']) ?> (<?= e((string) $portfolio['base_currency']) ?>)
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<div class="grid" style="grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:10px;">
|
||||
<label class="setup-field muted">
|
||||
<span>Aktienname</span>
|
||||
<input type="text" name="instrument_name" value="<?= e((string) ($editPosition['instrument_name'] ?? '')) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>API-Symbol / Ticker</span>
|
||||
<input type="text" name="symbol" value="<?= e((string) ($editPosition['symbol'] ?? '')) ?>" placeholder="z.B. AAPL oder MBG.DE">
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>ISIN</span>
|
||||
<input type="text" name="isin" value="<?= e((string) ($editPosition['isin'] ?? '')) ?>">
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>WKN</span>
|
||||
<input type="text" name="wkn" value="<?= e((string) ($editPosition['wkn'] ?? '')) ?>">
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Boerse / Markt</span>
|
||||
<input type="text" name="market" value="<?= e((string) ($editPosition['market'] ?? '')) ?>">
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Kurswaehrung</span>
|
||||
<input type="text" name="quote_currency" value="<?= e((string) ($editPosition['quote_currency'] ?? $defaultReportCurrency)) ?>" required>
|
||||
</label>
|
||||
</div>
|
||||
<div class="grid" style="grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:10px;">
|
||||
<label class="setup-field muted">
|
||||
<span>Stueckzahl</span>
|
||||
<input type="number" name="quantity" min="0" step="0.000001" value="<?= e((string) ($editPosition['quantity'] ?? '')) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Kaufpreis</span>
|
||||
<input type="number" name="purchase_price" min="0" step="0.00000001" value="<?= e((string) ($editPosition['purchase_price'] ?? '')) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Kaufwaehrung</span>
|
||||
<input type="text" name="purchase_currency" value="<?= e((string) ($editPosition['purchase_currency'] ?? $defaultReportCurrency)) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Kaufdatum</span>
|
||||
<input type="date" name="purchase_date" value="<?= e((string) ($editPosition['purchase_date'] ?? date('Y-m-d'))) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Gebuehren</span>
|
||||
<input type="number" name="fees" min="0" step="0.00000001" value="<?= e((string) ($editPosition['fees'] ?? '')) ?>">
|
||||
</label>
|
||||
</div>
|
||||
<label class="setup-field muted">
|
||||
<span>Notizen</span>
|
||||
<textarea name="position_notes" rows="3"><?= e((string) ($editPosition['notes'] ?? '')) ?></textarea>
|
||||
</label>
|
||||
<div class="bc-actions">
|
||||
<button class="bc-button bc-button--primary" type="submit">Position speichern</button>
|
||||
<?php if ($editPosition): ?>
|
||||
<a class="bc-button bc-button--secondary" href="/apps/boersenchecker?view=depotverwaltung<?= e($ownerQuery) ?>">Abbrechen</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Wertpapiersuche</h2>
|
||||
<p>Alpha-Vantage-Suchergebnisse pruefen und Daten direkt ins Positionsformular uebernehmen.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bc-section-copy">
|
||||
<form method="post" style="margin-top:16px; display:flex; gap:10px; flex-wrap:wrap; align-items:end;">
|
||||
<input type="hidden" name="action" value="search_symbol">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<label class="setup-field muted" style="margin:0; min-width:260px; flex:1;">
|
||||
<span>Suchbegriff</span>
|
||||
<input type="text" name="search_keywords" value="<?= e($symbolSearchKeywords) ?>" placeholder="z.B. Mercedes, AAPL, Allianz" required>
|
||||
</label>
|
||||
<button class="bc-button bc-button--primary" type="submit">Suchen</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php if ($symbolSearchResults !== []): ?>
|
||||
<table class="bc-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th>
|
||||
<th>Name</th>
|
||||
<th>Typ</th>
|
||||
<th>Region</th>
|
||||
<th>Waehrung</th>
|
||||
<th>Match</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($symbolSearchResults as $result): ?>
|
||||
<tr>
|
||||
<td><strong><?= e((string) ($result['symbol'] ?? '')) ?></strong></td>
|
||||
<td><?= e((string) ($result['name'] ?? '')) ?></td>
|
||||
<td><?= e((string) ($result['type'] ?? '')) ?></td>
|
||||
<td><?= e((string) ($result['region'] ?? '')) ?></td>
|
||||
<td><?= e((string) ($result['currency'] ?? '')) ?></td>
|
||||
<td><?= e((string) ($result['match_score'] ?? '')) ?></td>
|
||||
<td>
|
||||
<a class="bc-button bc-button--secondary" href="/apps/boersenchecker?view=depotverwaltung&owner_sub=<?= urlencode((string) $ownerSub) ?>&symbol_candidate=<?= urlencode((string) ($result['symbol'] ?? '')) ?>&instrument_name_candidate=<?= urlencode((string) ($result['name'] ?? '')) ?>&isin_candidate=<?= urlencode((string) ($result['isin'] ?? '')) ?>&market_candidate=<?= urlencode((string) ($result['region'] ?? '')) ?>"e_currency_candidate=<?= urlencode((string) ($result['currency'] ?? '')) ?>">
|
||||
In Formular uebernehmen
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php else: ?>
|
||||
<div class="bc-section-copy">
|
||||
<div class="muted">Noch keine Symbolsuche ausgefuehrt.</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Manuellen Kurs erfassen</h2>
|
||||
<p>Kurse mit Uhrzeit und Quelle direkt in die Historie schreiben.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($instrumentList === []): ?>
|
||||
<div class="muted" style="margin-top:16px;">Sobald Positionen vorhanden sind, koennen hier Kurse mit Uhrzeit gespeichert werden.</div>
|
||||
<?php else: ?>
|
||||
<form method="post" style="margin-top:16px; display:grid; gap:12px;">
|
||||
<input type="hidden" name="action" value="save_quote">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<div class="grid" style="grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:10px;">
|
||||
<label class="setup-field muted">
|
||||
<span>Aktie</span>
|
||||
<select name="quote_instrument_id" required>
|
||||
<option value="">Bitte waehlen</option>
|
||||
<?php foreach ($instrumentList as $instrument): ?>
|
||||
<option value="<?= e((string) $instrument['id']) ?>" <?= $selectedInstrumentForQuote === (int) $instrument['id'] ? 'selected' : '' ?>>
|
||||
<?= e((string) $instrument['name']) ?><?= $instrument['symbol'] !== '' ? ' (' . e((string) $instrument['symbol']) . ')' : '' ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Kurs</span>
|
||||
<input type="number" name="quote_price" min="0" step="0.00000001" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Waehrung</span>
|
||||
<input type="text" name="quote_currency" value="<?= e($selectedInstrumentQuoteCurrency) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Zeitpunkt</span>
|
||||
<input type="datetime-local" name="quoted_at" value="<?= e($localNowInputValue) ?>" required>
|
||||
</label>
|
||||
<label class="setup-field muted">
|
||||
<span>Quelle</span>
|
||||
<input type="text" name="quote_source" value="manual">
|
||||
</label>
|
||||
</div>
|
||||
<div class="bc-actions">
|
||||
<button class="bc-button bc-button--primary" type="submit">Kurs speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Depots</h2>
|
||||
<p>Uebersicht aller Depots mit Kennzahlen und Schnellaktionen.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($portfolios === []): ?>
|
||||
<div class="muted" style="margin-top:16px;">Noch keine Depots vorhanden.</div>
|
||||
<?php else: ?>
|
||||
<div class="bc-card-grid" style="margin-top:16px;">
|
||||
<?php foreach ($portfolios as $portfolio): ?>
|
||||
<?php
|
||||
$portfolioId = (int) $portfolio['id'];
|
||||
$stats = $portfolioStats[$portfolioId] ?? ['positions' => 0, 'invested' => 0.0, 'current' => 0.0, 'gain' => null, 'has_invested' => false, 'has_current' => false];
|
||||
?>
|
||||
<section class="card-box">
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap;">
|
||||
<div>
|
||||
<strong><?= e((string) $portfolio['name']) ?></strong>
|
||||
<div class="muted"><?= e((string) $portfolio['base_currency']) ?> · <?= e((string) $stats['positions']) ?> Position(en)</div>
|
||||
</div>
|
||||
<div class="bc-actions">
|
||||
<a class="bc-button bc-button--secondary" href="/apps/boersenchecker?view=depotverwaltung&owner_sub=<?= urlencode((string) $ownerSub) ?>&edit_portfolio=<?= e((string) $portfolioId) ?>">Bearbeiten</a>
|
||||
<form method="post" onsubmit="return confirm('Depot wirklich loeschen?')">
|
||||
<input type="hidden" name="action" value="delete_portfolio">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<input type="hidden" name="portfolio_id" value="<?= e((string) $portfolioId) ?>">
|
||||
<button class="bc-button bc-button--secondary" type="submit">Loeschen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!empty($portfolio['notes'])): ?>
|
||||
<div class="muted" style="margin-top:10px;"><?= e((string) $portfolio['notes']) ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="grid" style="margin-top:16px; grid-template-columns:repeat(auto-fit, minmax(140px, 1fr)); gap:10px;">
|
||||
<div class="bc-stat">
|
||||
<div class="muted">Investiert</div>
|
||||
<strong><?= $stats['has_invested'] ? e($fmtNumber((float) $stats['invested'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong>
|
||||
</div>
|
||||
<div class="bc-stat">
|
||||
<div class="muted">Aktuell</div>
|
||||
<strong><?= $stats['has_current'] ? e($fmtNumber((float) $stats['current'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong>
|
||||
</div>
|
||||
<div class="bc-stat">
|
||||
<div class="muted">Gewinn / Verlust</div>
|
||||
<strong><?= $stats['gain'] !== null ? e($fmtNumber((float) $stats['gain'])) . ' ' . e((string) $portfolio['base_currency']) : 'n/a' ?></strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Positionen</h2>
|
||||
<p>Alle Positionen mit Kaufdaten, letztem Kurs und aktuellen Werten.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($positions === []): ?>
|
||||
<div class="bc-section-copy">
|
||||
<div class="muted">Noch keine Positionen vorhanden.</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table class="bc-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Depot</th>
|
||||
<th>Aktie</th>
|
||||
<th>ISIN / WKN</th>
|
||||
<th>Stueck</th>
|
||||
<th>Kauf</th>
|
||||
<th>Letzter Kurs</th>
|
||||
<th>Wert</th>
|
||||
<th>Delta</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($positions as $position): ?>
|
||||
<tr>
|
||||
<td><?= e((string) ($portfolioById[(int) $position['portfolio_id']]['name'] ?? '')) ?></td>
|
||||
<td>
|
||||
<strong><?= e((string) $position['instrument_name']) ?></strong>
|
||||
<?php if (!empty($position['symbol'])): ?>
|
||||
<div class="muted"><?= e((string) $position['symbol']) ?></div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= e((string) ($position['isin'] ?: '-')) ?>
|
||||
<div class="muted"><?= e((string) ($position['wkn'] ?: '-')) ?></div>
|
||||
</td>
|
||||
<td><?= e($fmtNumber((float) $position['quantity'], 6)) ?></td>
|
||||
<td>
|
||||
<?= e($fmtNumber((float) $position['purchase_price'], 4)) ?> <?= e((string) $position['purchase_currency']) ?>
|
||||
<div class="muted"><?= e((string) $position['purchase_date']) ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($position['latest_price'] !== null): ?>
|
||||
<?= e($fmtNumber((float) $position['latest_price'], 4)) ?> <?= e((string) $position['latest_currency']) ?>
|
||||
<div class="muted"><?= e($fmtDateTime((string) $position['latest_quoted_at'], (string) ($position['latest_source'] ?? ''))) ?></div>
|
||||
<?php else: ?>
|
||||
<span class="muted">kein Kurs</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($position['current_total_base'] !== null): ?>
|
||||
<?= e($fmtNumber((float) $position['current_total_base'])) ?> <?= e((string) $position['base_currency']) ?>
|
||||
<?php else: ?>
|
||||
<span class="muted">n/a</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($position['gain_base'] !== null): ?>
|
||||
<?= e($fmtNumber((float) $position['gain_base'])) ?> <?= e((string) $position['base_currency']) ?>
|
||||
<?php else: ?>
|
||||
<span class="muted">n/a</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="bc-actions">
|
||||
<a class="bc-button bc-button--secondary" href="/apps/boersenchecker?view=depotverwaltung&owner_sub=<?= urlencode((string) $ownerSub) ?>&edit_position=<?= e((string) $position['id']) ?>">Bearbeiten</a>
|
||||
<a class="bc-button bc-button--secondary" href="/apps/boersenchecker?view=depotverwaltung&owner_sub=<?= urlencode((string) $ownerSub) ?>&instrument_id=<?= e((string) $position['instrument_id']) ?>">Kurs erfassen</a>
|
||||
<form method="post">
|
||||
<input type="hidden" name="action" value="refresh_market_data_position">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<input type="hidden" name="position_id" value="<?= e((string) $position['id']) ?>">
|
||||
<button class="bc-button bc-button--secondary" type="submit">API-Kurs</button>
|
||||
</form>
|
||||
<form method="post" onsubmit="return confirm('Position wirklich loeschen?')">
|
||||
<input type="hidden" name="action" value="delete_position">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<input type="hidden" name="position_id" value="<?= e((string) $position['id']) ?>">
|
||||
<button class="bc-button bc-button--secondary" type="submit">Loeschen</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Kursverlauf</h2>
|
||||
<p>Historische Kurse pro Aktie mit Zeitstempel und Quelle.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($instrumentList === []): ?>
|
||||
<div class="muted" style="margin-top:16px;">Noch keine Kursdaten vorhanden.</div>
|
||||
<?php else: ?>
|
||||
<div class="bc-card-grid" style="margin-top:16px;">
|
||||
<?php foreach ($instrumentList as $instrumentId => $instrument): ?>
|
||||
<?php $history = array_slice($quoteHistory[$instrumentId] ?? [], 0, 10); ?>
|
||||
<section class="card-box">
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap;">
|
||||
<div>
|
||||
<strong><?= e((string) $instrument['name']) ?></strong>
|
||||
<div class="muted">
|
||||
<?= e((string) ($instrument['symbol'] ?: '-')) ?> · <?= e((string) ($instrument['isin'] ?: '-')) ?>
|
||||
</div>
|
||||
</div>
|
||||
<a class="bc-button bc-button--secondary" href="/apps/boersenchecker?view=depotverwaltung&owner_sub=<?= urlencode((string) $ownerSub) ?>&instrument_id=<?= e((string) $instrumentId) ?>">Neuen Kurs erfassen</a>
|
||||
</div>
|
||||
<?php if ($history === []): ?>
|
||||
<div class="muted" style="margin-top:12px;">Noch keine historischen Kurse vorhanden.</div>
|
||||
<?php else: ?>
|
||||
<div class="bc-table-shell" style="margin-top:12px;">
|
||||
<table class="bc-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Zeitpunkt</th>
|
||||
<th>Kurs</th>
|
||||
<th>Quelle</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($history as $quote): ?>
|
||||
<tr>
|
||||
<td><?= e($fmtDateTime((string) $quote['quoted_at'], (string) ($quote['source'] ?? ''))) ?></td>
|
||||
<td><?= e($fmtNumber((float) $quote['price'], 4)) ?> <?= e((string) $quote['currency']) ?></td>
|
||||
<td><?= e((string) $quote['source']) ?></td>
|
||||
<td>
|
||||
<form method="post" onsubmit="return confirm('Kurseintrag wirklich loeschen?')">
|
||||
<input type="hidden" name="action" value="delete_quote">
|
||||
<input type="hidden" name="owner_sub" value="<?= e((string) $ownerSub) ?>">
|
||||
<input type="hidden" name="quote_id" value="<?= e((string) $quote['id']) ?>">
|
||||
<button class="bc-button bc-button--secondary" type="submit">Loeschen</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
</div>
|
||||
<?= module_shell_footer() ?>
|
||||
211
modules/boersenchecker/partials/home.php
Normal file
211
modules/boersenchecker/partials/home.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?= module_shell_header('boersenchecker', [
|
||||
'title' => 'Depot-Ueberblick',
|
||||
]) ?>
|
||||
<div class="bc-page" data-bc-home data-chart-endpoint="/api/boersenchecker/index.php?path=v1/chart-data">
|
||||
<script type="application/json" data-bc-instruments-json><?= json_encode(array_map(static function (array $position): array {
|
||||
return [
|
||||
'instrument_id' => (int) ($position['instrument_id'] ?? 0),
|
||||
'instrument_name' => (string) ($position['instrument_name'] ?? ''),
|
||||
'symbol' => (string) ($position['symbol'] ?? ''),
|
||||
'isin' => (string) ($position['isin'] ?? ''),
|
||||
];
|
||||
}, $positions), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?></script>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<section class="section-box"><div class="bc-alert bc-alert--error"><?= e($error) ?></div></section>
|
||||
<?php elseif ($notice): ?>
|
||||
<section class="section-box"><div class="bc-alert bc-alert--success"><?= e($notice) ?></div></section>
|
||||
<?php endif; ?>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Marktueberblick</h2>
|
||||
<p>Depotauswahl, Aktienfokus und aktueller Kursabruf in einem Bereich.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bc-toolbar" style="margin-top:16px;">
|
||||
<form class="bc-panel" method="get" action="/apps/boersenchecker">
|
||||
<input type="hidden" name="view" value="overview">
|
||||
<div class="bc-field-label">Depotauswahl</div>
|
||||
<?php if ($portfolios === []): ?>
|
||||
<div class="bc-text" style="margin-top:12px;">Keine Depots vorhanden.</div>
|
||||
<?php else: ?>
|
||||
<label class="setup-field" style="margin-top:12px;">
|
||||
<span class="bc-text">Depot</span>
|
||||
<select name="portfolio_id" onchange="this.form.submit()">
|
||||
<?php foreach ($portfolios as $portfolio): ?>
|
||||
<option value="<?= e((string) $portfolio['id']) ?>" <?= (string) $selectedPortfolioId === (string) $portfolio['id'] ? 'selected' : '' ?>>
|
||||
<?= e((string) $portfolio['name']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<form class="bc-panel" method="get" action="/apps/boersenchecker">
|
||||
<input type="hidden" name="view" value="overview">
|
||||
<input type="hidden" name="portfolio_id" value="<?= e((string) $selectedPortfolioId) ?>">
|
||||
<div class="bc-field-label">Aktienauswahl</div>
|
||||
<?php if ($positions === []): ?>
|
||||
<div class="bc-text" style="margin-top:12px;">Keine Aktien im ausgewaehlten Depot.</div>
|
||||
<?php else: ?>
|
||||
<label class="setup-field" style="margin-top:12px;">
|
||||
<span class="bc-text">Aktie</span>
|
||||
<select name="instrument_id" data-bc-instrument onchange="this.form.submit()">
|
||||
<?php foreach ($positions as $position): ?>
|
||||
<option value="<?= e((string) $position['instrument_id']) ?>" <?= (string) $selectedInstrumentId === (string) $position['instrument_id'] ? 'selected' : '' ?>>
|
||||
<?= e((string) $position['instrument_name']) ?><?= !empty($position['symbol']) ? ' (' . e((string) $position['symbol']) . ')' : '' ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<form class="bc-panel" method="post">
|
||||
<input type="hidden" name="action" value="refresh_current_quotes_home">
|
||||
<input type="hidden" name="portfolio_id" value="<?= e((string) $selectedPortfolioId) ?>">
|
||||
<div class="bc-field-label">Marktdaten</div>
|
||||
<p class="bc-text" style="margin-top:12px;">Aktuelle Kurse fuer das gewaehlte Depot ueber Alpha Vantage anhand des hinterlegten Symbols abrufen.</p>
|
||||
<div class="bc-actions" style="margin-top:16px;">
|
||||
<button class="bc-button bc-button--primary" type="submit" <?= $selectedPortfolioId > 0 ? '' : 'disabled' ?>>Aktuelle Kurse abrufen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="bc-overview-grid">
|
||||
<section class="card-box bc-stat">
|
||||
<div class="bc-field-label">Positionen</div>
|
||||
<div class="bc-stat-value"><?= e((string) ($summary['positions'] ?? 0)) ?></div>
|
||||
<div class="bc-text" style="margin-top:6px;">Aktien im aktuell gewaehlten Depot</div>
|
||||
</section>
|
||||
<section class="card-box bc-stat">
|
||||
<div class="bc-field-label">Investiert</div>
|
||||
<div class="bc-stat-value"><?= isset($summary['invested']) && $summary['invested'] !== null ? e(number_format((float) $summary['invested'], 2, ',', '.')) . ' ' . e($defaultReportCurrency) : 'n/a' ?></div>
|
||||
<div class="bc-text" style="margin-top:6px;">In Berichtswahrung bewertet</div>
|
||||
</section>
|
||||
<section class="card-box bc-stat">
|
||||
<div class="bc-field-label">Aktueller Wert</div>
|
||||
<div class="bc-stat-value"><?= isset($summary['current']) && $summary['current'] !== null ? e(number_format((float) $summary['current'], 2, ',', '.')) . ' ' . e($defaultReportCurrency) : 'n/a' ?></div>
|
||||
<div class="bc-text" style="margin-top:6px;">Basierend auf dem letzten gespeicherten Kurs</div>
|
||||
</section>
|
||||
<section class="card-box bc-stat">
|
||||
<div class="bc-field-label">Performance</div>
|
||||
<div class="bc-stat-value"><?= isset($summary['gain']) && $summary['gain'] !== null ? e(number_format((float) $summary['gain'], 2, ',', '.')) . ' ' . e($defaultReportCurrency) : 'n/a' ?></div>
|
||||
<div class="bc-text" style="margin-top:6px;"><?= !empty($summary['best']['instrument_name']) ? 'Top-Wert: ' . e((string) $summary['best']['instrument_name']) : 'Noch keine Vergleichsdaten' ?></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="bc-card-grid">
|
||||
<section class="card-box">
|
||||
<div class="bc-field-label">Bester Wert</div>
|
||||
<?php if (!empty($summary['best'])): ?>
|
||||
<div class="bc-stat-value"><?= e((string) $summary['best']['instrument_name']) ?></div>
|
||||
<div class="bc-pill-soft" style="margin-top:12px;"><?= e(number_format((float) ($summary['best']['gain_percent'] ?? 0), 2, ',', '.')) ?>%</div>
|
||||
<?php else: ?>
|
||||
<div class="bc-text" style="margin-top:12px;">Noch keine Performance verfuegbar.</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="card-box">
|
||||
<div class="bc-field-label">Schwaechster Wert</div>
|
||||
<?php if (!empty($summary['worst'])): ?>
|
||||
<div class="bc-stat-value"><?= e((string) $summary['worst']['instrument_name']) ?></div>
|
||||
<div class="bc-pill-soft" style="margin-top:12px;"><?= e(number_format((float) ($summary['worst']['gain_percent'] ?? 0), 2, ',', '.')) ?>%</div>
|
||||
<?php else: ?>
|
||||
<div class="bc-text" style="margin-top:12px;">Noch keine Performance verfuegbar.</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<?php foreach (array_slice($positions, 0, 2) as $position): ?>
|
||||
<section class="card-box bc-stat">
|
||||
<div class="bc-field-label"><?= e((string) $position['instrument_name']) ?></div>
|
||||
<div class="bc-stat-value"><?= $position['latest_price'] !== null ? e(number_format((float) $position['latest_price'], 2, ',', '.')) . ' ' . e((string) $position['latest_currency']) : 'n/a' ?></div>
|
||||
<div class="bc-text" style="margin-top:6px;"><?= e((string) (($position['latest_quoted_at'] ?? '') !== '' ? $fmtDateTime((string) $position['latest_quoted_at'], (string) ($position['latest_source'] ?? '')) : 'kein Kurs')) ?></div>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Kursverlauf</h2>
|
||||
<p>Schlusskurse ueber mehrere Zeitfenster fuer das aktuell gewaehlte Instrument.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bc-chart-card" style="margin-top:16px;">
|
||||
<div style="display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap; align-items:center;">
|
||||
<div>
|
||||
<div class="bc-field-label">Aktie</div>
|
||||
<div class="bc-stat-value" data-bc-instrument-name><?= e((string) ($selectedInstrument['instrument_name'] ?? 'Keine Aktie ausgewaehlt')) ?></div>
|
||||
<?php if ($selectedInstrument): ?>
|
||||
<div class="bc-text" data-bc-instrument-meta><?= e((string) ($selectedInstrument['symbol'] ?? '')) ?> · <?= e((string) ($selectedInstrument['isin'] ?? '-')) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="bc-range-list">
|
||||
<button type="button" class="bc-range-button" data-range="1d" aria-pressed="false">Tag</button>
|
||||
<button type="button" class="bc-range-button" data-range="5d" aria-pressed="false">5 Tage</button>
|
||||
<button type="button" class="bc-range-button" data-range="1m" aria-pressed="true">Monat</button>
|
||||
<button type="button" class="bc-range-button" data-range="3m" aria-pressed="false">3 Monate</button>
|
||||
<button type="button" class="bc-range-button" data-range="6m" aria-pressed="false">6 Monate</button>
|
||||
<button type="button" class="bc-range-button" data-range="1y" aria-pressed="false">Jahr</button>
|
||||
<button type="button" class="bc-range-button" data-range="5y" aria-pressed="false">5 Jahre</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bc-text" data-bc-chart-status style="margin-top:12px;">Chartdaten werden geladen...</div>
|
||||
<div class="bc-stat-value" data-bc-chart-summary style="margin-top:6px;">-</div>
|
||||
<div class="bc-chart-shell" data-bc-chart style="margin-top:18px;"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Aktien im Depot</h2>
|
||||
<p>Stueckzahl, Kaufdaten, letzter Kurs und Performance auf einen Blick.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bc-section-copy">
|
||||
<?php if ($positions === []): ?>
|
||||
<div class="bc-text" style="padding:0 0 18px;">Keine Aktien im ausgewaehlten Depot.</div>
|
||||
<?php else: ?>
|
||||
<div class="bc-position-list" style="padding:0 0 18px;">
|
||||
<?php foreach ($positions as $position): ?>
|
||||
<?php $gainClass = (($position['gain_report'] ?? 0) >= 0) ? 'is-positive' : 'is-negative'; ?>
|
||||
<div class="bc-position-row">
|
||||
<div>
|
||||
<strong><?= e((string) $position['instrument_name']) ?></strong>
|
||||
<div class="bc-text" style="margin-top:4px;"><?= e((string) ($position['symbol'] ?? '')) ?> · <?= e((string) ($position['isin'] ?? '-')) ?></div>
|
||||
<?php if (!empty($position['market'])): ?>
|
||||
<div class="bc-pill-soft" style="margin-top:10px;"><?= e((string) $position['market']) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div>
|
||||
<div class="bc-field-label">Stueckzahl</div>
|
||||
<div><?= e(number_format((float) $position['quantity'], 6, ',', '.')) ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="bc-field-label">Kaufpreis</div>
|
||||
<div><?= e(number_format((float) $position['purchase_price'], 2, ',', '.')) ?> <?= e((string) $position['purchase_currency']) ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="bc-field-label">Letzter Kurs</div>
|
||||
<div><?= $position['latest_price'] !== null ? e(number_format((float) $position['latest_price'], 2, ',', '.')) . ' ' . e((string) $position['latest_currency']) : 'n/a' ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="bc-field-label">Performance</div>
|
||||
<div class="bc-performance <?= e($gainClass) ?>">
|
||||
<?= isset($position['gain_report']) && $position['gain_report'] !== null ? e(number_format((float) $position['gain_report'], 2, ',', '.')) . ' ' . e($defaultReportCurrency) : 'n/a' ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<?= module_shell_footer() ?>
|
||||
188
modules/boersenchecker/partials/instruments.php
Normal file
188
modules/boersenchecker/partials/instruments.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<?= module_shell_header('boersenchecker', [
|
||||
'title' => 'Aktienverwaltung',
|
||||
]) ?>
|
||||
<div class="bc-page">
|
||||
<?php if ($error): ?>
|
||||
<section class="section-box"><div class="bc-alert bc-alert--error"><?= e($error) ?></div></section>
|
||||
<?php elseif ($notice): ?>
|
||||
<section class="section-box"><div class="bc-alert bc-alert--success"><?= e($notice) ?></div></section>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="bc-card-grid">
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Aktie waehlen</h2>
|
||||
<p>Systemweit vorhandene Aktie aus allen Depots auswaehlen.</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="get" action="/apps/boersenchecker" style="margin-top:16px;">
|
||||
<input type="hidden" name="view" value="aktienverwaltung">
|
||||
<label class="setup-field muted">
|
||||
<span>Aktien aller Depots</span>
|
||||
<select name="instrument_id" onchange="this.form.submit()">
|
||||
<?php foreach ($instruments as $instrument): ?>
|
||||
<option value="<?= e((string) $instrument['id']) ?>" <?= (string) $selectedInstrumentId === (string) $instrument['id'] ? 'selected' : '' ?>>
|
||||
<?= e((string) $instrument['name']) ?><?= !empty($instrument['symbol']) ? ' (' . e((string) $instrument['symbol']) . ')' : '' ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Wertpapiersuche</h2>
|
||||
<p>Alpha-Vantage-Suchergebnisse finden und direkt fuer die Aktie uebernehmen.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bc-section-copy">
|
||||
<form method="post" style="margin-top:16px; display:flex; gap:10px; flex-wrap:wrap; align-items:end;">
|
||||
<input type="hidden" name="action" value="search_symbol">
|
||||
<input type="hidden" name="instrument_id" value="<?= e((string) $selectedInstrumentId) ?>">
|
||||
<label class="setup-field muted" style="margin:0; min-width:260px; flex:1;">
|
||||
<span>Suchbegriff</span>
|
||||
<input type="text" name="search_keywords" value="<?= e($searchKeywords) ?>" placeholder="z.B. Apple, AAPL, Allianz" required>
|
||||
</label>
|
||||
<button class="bc-button bc-button--primary" type="submit">Suchen</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php if ($searchResults !== []): ?>
|
||||
<table class="bc-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th>
|
||||
<th>Name</th>
|
||||
<th>Region</th>
|
||||
<th>Waehrung</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($searchResults as $result): ?>
|
||||
<tr>
|
||||
<td><strong><?= e((string) ($result['symbol'] ?? '')) ?></strong></td>
|
||||
<td><?= e((string) ($result['name'] ?? '')) ?></td>
|
||||
<td><?= e((string) ($result['region'] ?? '')) ?></td>
|
||||
<td><?= e((string) ($result['currency'] ?? '')) ?></td>
|
||||
<td>
|
||||
<a class="bc-button bc-button--secondary" href="/apps/boersenchecker?view=aktienverwaltung&instrument_id=<?= e((string) $selectedInstrumentId) ?>&symbol_candidate=<?= urlencode((string) ($result['symbol'] ?? '')) ?>&instrument_name_candidate=<?= urlencode((string) ($result['name'] ?? '')) ?>&isin_candidate=<?= urlencode((string) ($result['isin'] ?? '')) ?>&market_candidate=<?= urlencode((string) ($result['region'] ?? '')) ?>"e_currency_candidate=<?= urlencode((string) ($result['currency'] ?? '')) ?>">
|
||||
Uebernehmen
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php else: ?>
|
||||
<div class="bc-section-copy">
|
||||
<div class="muted">Noch keine Symbolsuche ausgefuehrt.</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Aktie bearbeiten</h2>
|
||||
<p>Stammdaten, Markt und Kurswaehrung zentral fuer die Aktie pflegen.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!$selectedInstrument || empty($selectedInstrument['id'])): ?>
|
||||
<div class="muted" style="margin-top:16px;">Keine Aktie vorhanden.</div>
|
||||
<?php else: ?>
|
||||
<form method="post" style="margin-top:16px; display:grid; gap:12px;">
|
||||
<input type="hidden" name="action" value="save_instrument">
|
||||
<input type="hidden" name="instrument_id" value="<?= e((string) ($selectedInstrument['id'] ?? 0)) ?>">
|
||||
<div class="grid" style="grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:10px;">
|
||||
<label class="setup-field muted"><span>Name</span><input type="text" name="instrument_name" value="<?= e((string) (($selectedInstrument['name'] ?? '') ?: ($_GET['instrument_name_candidate'] ?? ''))) ?>" required></label>
|
||||
<label class="setup-field muted"><span>Symbol</span><input type="text" name="symbol" value="<?= e((string) (($selectedInstrument['symbol'] ?? '') ?: ($_GET['symbol_candidate'] ?? ''))) ?>"></label>
|
||||
<label class="setup-field muted"><span>ISIN</span><input type="text" name="isin" value="<?= e((string) $selectedInstrument['isin'] ?? '') ?>"></label>
|
||||
<label class="setup-field muted"><span>WKN</span><input type="text" name="wkn" value="<?= e((string) $selectedInstrument['wkn'] ?? '') ?>"></label>
|
||||
<label class="setup-field muted"><span>Markt</span><input type="text" name="market" value="<?= e((string) (($selectedInstrument['market'] ?? '') ?: ($_GET['market_candidate'] ?? ''))) ?>"></label>
|
||||
<label class="setup-field muted"><span>Kurswaehrung</span><input type="text" name="quote_currency" value="<?= e((string) (($selectedInstrument['quote_currency'] ?? $defaultReportCurrency) ?: ($_GET['quote_currency_candidate'] ?? $defaultReportCurrency))) ?>"></label>
|
||||
</div>
|
||||
<div class="bc-actions">
|
||||
<button class="bc-button bc-button--primary" type="submit">Aktie speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
<form method="post" style="margin-top:12px;">
|
||||
<input type="hidden" name="action" value="refresh_market_data_instrument">
|
||||
<input type="hidden" name="instrument_id" value="<?= e((string) ($selectedInstrument['id'] ?? 0)) ?>">
|
||||
<button class="bc-button bc-button--secondary" type="submit">Aktuellen API-Kurs abrufen</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Manuellen Kurs eingeben</h2>
|
||||
<p>Einzelne Kurse mit Zeitstempel und Quelle fuer die ausgewaehlte Aktie speichern.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!$selectedInstrument || empty($selectedInstrument['id'])): ?>
|
||||
<div class="muted" style="margin-top:16px;">Keine Aktie vorhanden.</div>
|
||||
<?php else: ?>
|
||||
<form method="post" style="margin-top:16px; display:grid; gap:12px;">
|
||||
<input type="hidden" name="action" value="save_quote">
|
||||
<input type="hidden" name="instrument_id" value="<?= e((string) ($selectedInstrument['id'] ?? 0)) ?>">
|
||||
<div class="grid" style="grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:10px;">
|
||||
<label class="setup-field muted"><span>Kurs</span><input type="number" name="quote_price" min="0" step="0.00000001" required></label>
|
||||
<label class="setup-field muted"><span>Waehrung</span><input type="text" name="quote_currency" value="<?= e((string) ($selectedInstrument['quote_currency'] ?? $defaultReportCurrency)) ?>" required></label>
|
||||
<label class="setup-field muted"><span>Zeitpunkt</span><input type="datetime-local" name="quoted_at" value="<?= e($localNowInputValue) ?>" required></label>
|
||||
<label class="setup-field muted"><span>Quelle</span><input type="text" name="quote_source" value="manual"></label>
|
||||
</div>
|
||||
<div class="bc-actions">
|
||||
<button class="bc-button bc-button--primary" type="submit">Kurs speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<section class="section-box">
|
||||
<div class="bc-section-head">
|
||||
<div>
|
||||
<h2 class="bc-section-title">Kursverlauf</h2>
|
||||
<p>Gespeicherte Kursdaten der ausgewaehlten Aktie mit Quelle und Loeschoption.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($quotes === []): ?>
|
||||
<div class="bc-section-copy">
|
||||
<div class="muted">Keine Kursdaten vorhanden.</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table class="bc-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Zeitpunkt</th>
|
||||
<th>Kurs</th>
|
||||
<th>Quelle</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($quotes as $quote): ?>
|
||||
<tr>
|
||||
<td><?= e($fmtDateTime((string) $quote['quoted_at'], (string) ($quote['source'] ?? ''))) ?></td>
|
||||
<td><?= e(number_format((float) $quote['price'], 4, ',', '.')) ?> <?= e((string) $quote['currency']) ?></td>
|
||||
<td><?= e((string) $quote['source']) ?></td>
|
||||
<td>
|
||||
<form method="post" onsubmit="return confirm('Kurseintrag wirklich loeschen?')">
|
||||
<input type="hidden" name="action" value="delete_quote">
|
||||
<input type="hidden" name="instrument_id" value="<?= e((string) $selectedInstrumentId) ?>">
|
||||
<input type="hidden" name="quote_id" value="<?= e((string) $quote['id']) ?>">
|
||||
<button class="bc-button bc-button--secondary" type="submit">Loeschen</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
</div>
|
||||
<?= module_shell_footer() ?>
|
||||
Reference in New Issue
Block a user