Aus der Kachel QIF-Import wird Import/Export mit je einem Knopf für beide Richtungen; davor steht die Wahl des Dateiformats (QIF oder CSV), die als Dialog und ohne Skript als eigene Seite funktioniert. - CsvBuchungsImport/CsvTabelle: Buchungen samt Splitzeilen, Spalten über die Kopfzeile, dieselbe Dublettenerkennung und der Trockenlauf wie beim QIF. - BuchungsExport/ExportController: Filter nach Zeitraum, Konto, Kategorie und Klasse; die Datei entsteht im Speicher, ein Exportverzeichnis gibt es nicht. - Housekeeping: Hochgeladene Importdateien und data/tmp werden nach der eingestellten Frist gelöscht (Vorgabe 14 Tage, 0 schaltet ab). Migration 013, Test 29 sowie E2E-Spec importexport.spec.js. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
244 lines
11 KiB
PHP
244 lines
11 KiB
PHP
<?php
|
||
|
||
use Finanzmanager\View;
|
||
|
||
/**
|
||
* Ergebnis und Erläuterungen des QIF-Imports. Eingebunden aus import.php,
|
||
* das die Datei- und Uploadkacheln beisteuert.
|
||
*/
|
||
|
||
/** @var array<string,mixed>|null $ergebnis */
|
||
/** @var array<string,mixed>|null $buchungen */
|
||
/** @var array<string,mixed>|null $vorlagen */
|
||
/** @var string $stichtag */
|
||
/** @var string $bis */
|
||
/** @var string $datei */
|
||
/** @var array<string,int> $dateikonten */
|
||
/** @var list<string> $auswahl */
|
||
/** @var string $csrfToken */
|
||
|
||
$bereiche = [
|
||
'klassen' => 'Klassen',
|
||
'kategorien' => 'Kategorien',
|
||
'konten' => 'Konten',
|
||
];
|
||
?>
|
||
|
||
<?php if ($ergebnis !== null): ?>
|
||
<div class="kachel">
|
||
<header>
|
||
<h2><?= $ergebnis['trockenlauf'] ? 'Trockenlauf' : 'Import abgeschlossen' ?></h2>
|
||
<span class="phasenmarke"><?= View::h($datei) ?></span>
|
||
</header>
|
||
|
||
<?php if ($ergebnis['trockenlauf']): ?>
|
||
<p class="hinweis">
|
||
Nichts wurde gespeichert. Die Zahlen zeigen, was ein Import anlegen würde.
|
||
</p>
|
||
<?php endif; ?>
|
||
|
||
<table class="liste">
|
||
<thead>
|
||
<tr>
|
||
<th>Bereich</th>
|
||
<th class="rechts"><?= $ergebnis['trockenlauf'] ? 'Neu' : 'Angelegt' ?></th>
|
||
<th class="rechts">Schon vorhanden</th>
|
||
<th class="rechts">Fehler</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($bereiche as $schluessel => $beschriftung): ?>
|
||
<tr>
|
||
<td><?= View::h($beschriftung) ?></td>
|
||
<td class="rechts"><?= (int)$ergebnis[$schluessel]['neu'] ?></td>
|
||
<td class="rechts nebentext"><?= (int)$ergebnis[$schluessel]['vorhanden'] ?></td>
|
||
<td class="rechts <?= (int)$ergebnis[$schluessel]['fehler'] > 0 ? 'betrag negativ' : 'nebentext' ?>">
|
||
<?= (int)$ergebnis[$schluessel]['fehler'] ?>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<tr>
|
||
<td>Kontengruppen</td>
|
||
<td class="rechts nebentext" colspan="3">
|
||
nicht im QIF-Export enthalten – <a href="/verwaltung/kontengruppen">hier zuordnen</a>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p class="hinweis">
|
||
Der FinanzManager exportiert je Konto nur Name, Kontoart, Beschreibung und
|
||
Kreditlimit. Die Zuordnung zu einer Kontengruppe steht weder im QIF noch in der
|
||
<code>QSD</code>-Datei; sie wird deshalb einmalig in der Verwaltung nachgetragen.
|
||
</p>
|
||
|
||
<?php if ($buchungen !== null): ?>
|
||
<h3>Buchungen</h3>
|
||
<table class="liste">
|
||
<tbody>
|
||
<tr>
|
||
<td><?= $buchungen['trockenlauf'] ? 'Neu' : 'Angelegt' ?></td>
|
||
<td class="rechts"><?= (int)$buchungen['buchungen']['neu'] ?></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="nebentext">schon vorhanden</td>
|
||
<td class="rechts nebentext"><?= (int)$buchungen['buchungen']['vorhanden'] ?></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="nebentext">
|
||
vor dem Stichtag – in den Anfangssaldo von
|
||
<?= (int)$buchungen['anfangssalden']['konten'] ?> Konten verrechnet
|
||
</td>
|
||
<td class="rechts nebentext"><?= (int)$buchungen['buchungen']['vor_stichtag'] ?></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="nebentext">nach dem Enddatum – vorausberechnet, verworfen</td>
|
||
<td class="rechts nebentext"><?= (int)$buchungen['buchungen']['zukunft'] ?></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="nebentext">darunter Wertpapiergeschäfte (Depot- und Geldbuchung)</td>
|
||
<td class="rechts nebentext"><?= (int)$buchungen['buchungen']['wertpapier'] ?></td>
|
||
</tr>
|
||
<?php if ((int)($buchungen['buchungen']['nicht_gewaehlt'] ?? 0) > 0): ?>
|
||
<tr>
|
||
<td class="nebentext">gehört zu keinem der gewählten Konten</td>
|
||
<td class="rechts nebentext"><?= (int)$buchungen['buchungen']['nicht_gewaehlt'] ?></td>
|
||
</tr>
|
||
<?php endif; ?>
|
||
<tr>
|
||
<td>Fehler</td>
|
||
<td class="rechts <?= (int)$buchungen['buchungen']['fehler'] > 0 ? 'betrag negativ' : 'nebentext' ?>">
|
||
<?= (int)$buchungen['buchungen']['fehler'] ?>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="hinweis">
|
||
Zeitraum <?= View::datum($buchungen['stichtag']) ?> bis <?= View::datum($buchungen['bis']) ?>.
|
||
Alles davor ist nicht verloren: es steckt im Anfangssaldo der Konten.
|
||
<?php if (($buchungen['konten'] ?? null) !== null): ?>
|
||
Übernommen wurden nur die Buchungen von
|
||
<strong><?= View::h(implode(', ', $buchungen['konten'])) ?></strong> – einschließlich
|
||
der Umbuchungen, die auf einem anderen Konto erfasst wurden und hierher zeigen.
|
||
Die Anfangssalden der übrigen Konten bleiben unangetastet.
|
||
<?php endif; ?>
|
||
</p>
|
||
<?php endif; ?>
|
||
|
||
<?php if (($vorlagen ?? null) !== null): ?>
|
||
<h3>Buchungsvorlagen</h3>
|
||
<table class="liste">
|
||
<tbody>
|
||
<tr>
|
||
<td><?= $buchungen !== null && $buchungen['trockenlauf'] ? 'Neu' : 'Angelegt' ?></td>
|
||
<td class="rechts"><?= (int)$vorlagen['neu'] ?></td>
|
||
</tr>
|
||
<tr>
|
||
<td class="nebentext">bereits vorhanden</td>
|
||
<td class="rechts nebentext"><?= (int)$vorlagen['vorhanden'] ?></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Fehler</td>
|
||
<td class="rechts <?= (int)$vorlagen['fehler'] > 0 ? 'betrag negativ' : 'nebentext' ?>">
|
||
<?= (int)$vorlagen['fehler'] ?>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="hinweis">
|
||
Der FinanzManager merkt sich jede erfasste Zahlung als Vorlage – im
|
||
Beispielexport sind das mehrere hundert. Sie stehen danach unter
|
||
<a href="/vorlagen">Buchungsvorlagen</a>.
|
||
</p>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($ergebnis['abschnitte'])): ?>
|
||
<h3>Inhalt der Datei</h3>
|
||
<p class="hinweis">
|
||
<?php $teile = [];
|
||
foreach ($ergebnis['abschnitte'] as $typ => $anzahl) {
|
||
$teile[] = View::h((string)$typ) . ': ' . (int)$anzahl;
|
||
}
|
||
echo implode(' · ', $teile); ?>
|
||
</p>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($ergebnis['meldungen'])): ?>
|
||
<h3>Protokoll</h3>
|
||
<ul class="protokoll">
|
||
<?php foreach ($ergebnis['meldungen'] as $meldung): ?>
|
||
<li class="<?= View::h($meldung['typ']) ?>"><?= View::h($meldung['text']) ?></li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($ergebnis['trockenlauf']): ?>
|
||
<form method="post" action="/verwaltung/import/ausfuehren" class="formular">
|
||
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken) ?>">
|
||
<input type="hidden" name="datei" value="<?= View::h($datei) ?>">
|
||
<input type="hidden" name="stichtag" value="<?= View::h($stichtag) ?>">
|
||
<input type="hidden" name="bis" value="<?= View::h($bis) ?>">
|
||
|
||
<?php if ($dateikonten !== []): ?>
|
||
<h3>Konten</h3>
|
||
<p class="feldhinweis">
|
||
Zur Wahl stehen die Konten, die in dieser Datei vorkommen. Ohne Häkchen
|
||
zählt die ganze Datei. Eine Umbuchung kommt mit, sobald eines der beiden
|
||
Konten gewählt ist – sie steht im Export nur einmal, beim erfassenden
|
||
Konto. Die Zahl nennt die Einträge, die das Konto berühren.
|
||
</p>
|
||
<div class="auswahlliste">
|
||
<?php foreach ($dateikonten as $name => $anzahl): ?>
|
||
<label class="ankreuzfeld">
|
||
<input type="checkbox" name="konten[]" value="<?= View::h((string)$name) ?>"
|
||
<?= $auswahl === [] || in_array((string)$name, $auswahl, true) ? 'checked' : '' ?>>
|
||
<span>
|
||
<?= View::h((string)$name) ?>
|
||
<span class="nebentext"><?= (int)$anzahl ?></span>
|
||
</span>
|
||
</label>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<div class="knopfleiste">
|
||
<button type="submit" name="modus" value="import" class="knopf primaer">Jetzt übernehmen</button>
|
||
<?php if ($dateikonten !== []): ?>
|
||
<button type="submit" name="modus" value="vorschau" class="knopf">
|
||
Trockenlauf mit dieser Auswahl
|
||
</button>
|
||
<?php endif; ?>
|
||
</div>
|
||
</form>
|
||
<?php else: ?>
|
||
<div class="knopfleiste">
|
||
<a href="/konten" class="knopf primaer">Kontenübersicht</a>
|
||
<a href="/verwaltung/kontengruppen" class="knopf">Kontengruppen</a>
|
||
<a href="/verwaltung/kategorien" class="knopf">Kategorien</a>
|
||
</div>
|
||
<p class="hinweis">
|
||
Die Anfangssalden wurden aus dem Zeitraum vor dem Stichtag berechnet. In der
|
||
Kontenübersicht lässt sich jeder Wert nachträglich ändern – ebenso das
|
||
Kennzeichen, ob ein Konto zur Summe der Kontostände zählt.
|
||
</p>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<div class="kachel">
|
||
<header><h2>So läuft der QIF-Import</h2></header>
|
||
|
||
<p class="hinweis">
|
||
Übernommen werden Buchungen ab <strong><?= View::datum($stichtag) ?></strong> bis
|
||
<strong><?= View::datum($bis) ?></strong>. Alles davor fließt in den Anfangssaldo der
|
||
Konten, alles danach gilt als Vorausberechnung des FinanzManagers und bleibt draußen.
|
||
Der Stichtag steht in den <a href="/einstellungen?bereich=import">Einstellungen</a>.
|
||
</p>
|
||
|
||
<p class="hinweis">
|
||
Soll nur ein Teil der Konten übernommen werden, zuerst den <strong>Trockenlauf</strong>
|
||
starten: danach steht fest, welche Konten die Datei führt, und sie stehen einzeln zur
|
||
Wahl. <strong>Importieren</strong> übernimmt die ganze Datei – Klassen, Kategorien,
|
||
Konten, Buchungen und Buchungsvorlagen in einem Zug.
|
||
</p>
|
||
</div>
|