look ahead

This commit is contained in:
davmar
2026-09-10 00:35:54 +02:00
parent 91d6dc9e54
commit 5b22fc8694
20 changed files with 2942 additions and 799 deletions
+28 -2
View File
@@ -47,15 +47,30 @@ bool isSameTransaction(BankTransaction a, BankTransaction b) {
int _amountCents(double amount) => (amount * 100).round();
/// Coarse bucket so fuzzy [isSameTransaction] only compares likely peers.
String _dedupeBucket(BankTransaction tx) =>
'${tx.date}|${tx.currency.toUpperCase()}|${_amountCents(tx.amount)}';
/// Merge [extra] into [existing], skipping duplicates. Newest date first.
List<BankTransaction> mergeTransactions(
List<BankTransaction> existing,
List<BankTransaction> extra,
) {
if (extra.isEmpty) return existing;
final buckets = <String, List<BankTransaction>>{};
for (final tx in existing) {
buckets.putIfAbsent(_dedupeBucket(tx), () => []).add(tx);
}
final out = List<BankTransaction>.of(existing);
for (final tx in extra) {
if (out.any((e) => isSameTransaction(e, tx))) continue;
final key = _dedupeBucket(tx);
final peers = buckets[key];
if (peers != null && peers.any((e) => isSameTransaction(e, tx))) {
continue;
}
out.add(tx);
buckets.putIfAbsent(key, () => []).add(tx);
}
out.sort((a, b) {
final byDate = b.date.compareTo(a.date);
@@ -70,9 +85,20 @@ List<BankTransaction> filterNewTransactions(
List<BankTransaction> existing,
List<BankTransaction> candidates,
) {
if (candidates.isEmpty) return const [];
if (existing.isEmpty) return List<BankTransaction>.of(candidates);
final buckets = <String, List<BankTransaction>>{};
for (final tx in existing) {
buckets.putIfAbsent(_dedupeBucket(tx), () => []).add(tx);
}
return [
for (final tx in candidates)
if (!existing.any((e) => isSameTransaction(e, tx))) tx,
if (!(buckets[_dedupeBucket(tx)]
?.any((e) => isSameTransaction(e, tx)) ??
false))
tx,
];
}