feat: Certain fragt in der Buchungsliste nach, ob es ein Uebertrag ist
Die Erkennung gab es laengst – aber nur auf der Seite "Zu erledigen", in einer Karte, die man erst finden muss. Wer in der Buchungsliste steht und die zweite Haelfte eines Uebertrags sieht, greift stattdessen zum ↔-Knopf und legt einen zweiten Uebertrag an. Genau so ist heute eine Zahlung doppelt verschoben worden. Jetzt steht die Frage in der Zeile: "Uebertrag von/nach Revolut CHF?" mit Verbinden und Ignorieren. Ignorieren wird gemerkt, sonst fragte Certain bei jedem Laden erneut. Dafuer gibt es die Suche jetzt auch als reines Nachschlagen: ``finde`` mit ``nur_vorschlaege`` verknuepft nichts, und dahinter liegt GET /uebertraege/vorschlaege. Eine Ansicht, die bloss fragt, darf beim Hinsehen nichts veraendern – sonst entschiede das Anschauen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,8 @@ export default function Transactions() {
|
||||
const [txns, setTxns] = useState([]);
|
||||
// Je Buchungs-ID die Gegenseite, falls sie Teil eines Übertrags ist.
|
||||
const [links, setLinks] = useState({});
|
||||
// Und je Buchungs-ID die Gegenseite, die es sein KÖNNTE – noch unbestätigt.
|
||||
const [vorschlag, setVorschlag] = useState({});
|
||||
// Buchung, die gerade zum Übertrag gemacht wird.
|
||||
const [uebertrag, setUebertrag] = useState(null);
|
||||
const [accounts, setAccounts] = useState([]);
|
||||
@@ -73,12 +75,21 @@ export default function Transactions() {
|
||||
try {
|
||||
// Verknüpfungen getrennt: Sie sind eine Schicht über den Buchungen,
|
||||
// kein Feld an ihnen – deshalb auch ein eigener Abruf.
|
||||
const [liste, verkn] = await Promise.all([
|
||||
const [liste, verkn, vorschlaege] = await Promise.all([
|
||||
api.listTransactions({ account_id: filter.account_id, type: filter.type }),
|
||||
api.transactionLinks().catch(() => ({})),
|
||||
// Nur fragen, nichts tun: Beim Anschauen der Liste darf nichts
|
||||
// verknüpft werden.
|
||||
api.transferSuggestions().catch(() => ({ vorschlaege: [] })),
|
||||
]);
|
||||
setTxns(liste);
|
||||
setLinks(verkn);
|
||||
const paare = {};
|
||||
for (const v of vorschlaege.vorschlaege || []) {
|
||||
paare[v.a.id] = v.b;
|
||||
paare[v.b.id] = v.a;
|
||||
}
|
||||
setVorschlag(paare);
|
||||
} catch (err) {
|
||||
toast(err.message, "error");
|
||||
}
|
||||
@@ -96,6 +107,29 @@ export default function Transactions() {
|
||||
}
|
||||
}
|
||||
|
||||
async function verbinden(tx) {
|
||||
const gegen = vorschlag[tx.id];
|
||||
if (!gegen) return;
|
||||
try {
|
||||
await api.connectTransfer(tx.id, gegen.id);
|
||||
ladenBuchungen();
|
||||
} catch (err) {
|
||||
toast(err.message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function nichtVerbinden(tx) {
|
||||
const gegen = vorschlag[tx.id];
|
||||
if (!gegen) return;
|
||||
try {
|
||||
// Ablehnen wird gemerkt, sonst fragt Certain bei jedem Laden erneut.
|
||||
await api.ignoreTransfer(tx.id, gegen.id);
|
||||
ladenBuchungen();
|
||||
} catch (err) {
|
||||
toast(err.message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function loesen(tx) {
|
||||
const link = links[String(tx.id)];
|
||||
if (!link) return;
|
||||
@@ -280,6 +314,27 @@ export default function Transactions() {
|
||||
|| t("transfers.linked")}
|
||||
</div>
|
||||
)}
|
||||
{/* Nachträglich erkannt: Auf einem anderen Konto steht der
|
||||
gleiche Betrag am selben Tag in die andere Richtung. Fragen
|
||||
statt tun – und die Antwort merken. */}
|
||||
{!links[String(tx.id)] && vorschlag[tx.id] && (
|
||||
<div className="uebertrag-frage">
|
||||
<Icon name="arrow-left-right" size={12} />
|
||||
<span className="ellipsis">
|
||||
{t("transfers.question", {
|
||||
konto: accountById[vorschlag[tx.id].account_id]?.name || "?",
|
||||
})}
|
||||
</span>
|
||||
<button type="button" className="btn sm"
|
||||
onClick={() => verbinden(tx)}>
|
||||
{t("transfers.connect")}
|
||||
</button>
|
||||
<button type="button" className="btn sm ghost"
|
||||
onClick={() => nichtVerbinden(tx)}>
|
||||
{t("transfers.ignore")}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -356,7 +411,7 @@ export default function Transactions() {
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
], [accountById, categoryById, baseCurrency, expenseGroups, incomeGroups,
|
||||
formatDate, links, t]);
|
||||
formatDate, links, vorschlag, t]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user