129 lines
4.0 KiB
Dart
129 lines
4.0 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:myapp/models/bank.dart';
|
|
import 'package:myapp/services/ing_csv_import.dart';
|
|
|
|
void main() {
|
|
test('parses ING Dutch semicolon CSV with Af/Bij and YYYYMMDD', () {
|
|
const raw = '''
|
|
"Datum";"Naam / Omschrijving";"Rekening";"Tegenrekening";"Code";"Af Bij";"Bedrag (EUR)";"Mutatiesoort";"Mededelingen"
|
|
"20260901";"AH CAMPUS DIEMEN";"NL00INGB0000000000";"";"GT";"Af";"12,50";"Betaalautomaat";"Pasvolgnr: 001"
|
|
"20260902";"SALARIS";"NL00INGB0000000000";"NL00ABCD";"OV";"Bij";"2000,00";"Overboeking";"Salaris september"
|
|
''';
|
|
final txs = parseIngCsv(raw);
|
|
expect(txs, hasLength(2));
|
|
expect(txs[0].date, '2026-09-01');
|
|
expect(txs[0].amount, -12.5);
|
|
expect(txs[0].description, contains('AH CAMPUS'));
|
|
expect(txs[1].date, '2026-09-02');
|
|
expect(txs[1].amount, 2000);
|
|
});
|
|
|
|
test('skips duplicates against existing API-like rows', () {
|
|
final existing = [
|
|
const BankTransaction(
|
|
date: '2026-09-01',
|
|
description:
|
|
'BCK*AH CAMPUS DIEMEN ZUID NLD Pasvolgnr: 001 Transactie: C00338',
|
|
amount: -12.5,
|
|
currency: 'EUR',
|
|
pending: false,
|
|
),
|
|
];
|
|
const raw = '''
|
|
Datum,Naam / Omschrijving,Rekening,Tegenrekening,Code,Af Bij,Bedrag (EUR),Mutatiesoort,Mededelingen
|
|
20260901,AH CAMPUS DIEMEN,,,,Af,"12,50",Betaalautomaat,Pasvolgnr: 001
|
|
20260903,JUMBO,,,,Af,"8,00",Betaalautomaat,
|
|
''';
|
|
final result = importIngCsvAgainst(raw: raw, existing: existing);
|
|
expect(result.parsed, 2);
|
|
expect(result.skippedDuplicates, 1);
|
|
expect(result.added, hasLength(1));
|
|
expect(result.added.single.description, contains('JUMBO'));
|
|
});
|
|
|
|
test('isSameTransaction matches merchant fingerprints', () {
|
|
const api = BankTransaction(
|
|
date: '2026-09-01',
|
|
description: 'BCK*AH CAMPUS DIEMEN ZUID NLD Pasvolgnr: 001 Transactie: X',
|
|
amount: -3.5,
|
|
currency: 'EUR',
|
|
pending: false,
|
|
);
|
|
const csv = BankTransaction(
|
|
date: '2026-09-01',
|
|
description: 'AH CAMPUS DIEMEN · Pasvolgnr: 001',
|
|
amount: -3.5,
|
|
currency: 'EUR',
|
|
pending: false,
|
|
);
|
|
expect(isSameTransaction(api, csv), isTrue);
|
|
});
|
|
|
|
test('API merge drops stale pending not returned by the bank', () {
|
|
const stalePending = BankTransaction(
|
|
date: '2026-09-01',
|
|
description: 'AH CAMPUS DIEMEN',
|
|
amount: -12.5,
|
|
currency: 'EUR',
|
|
pending: true,
|
|
);
|
|
const settled = BankTransaction(
|
|
date: '2026-09-03',
|
|
description: 'BCK*AH CAMPUS DIEMEN ZUID NLD',
|
|
amount: -12.5,
|
|
currency: 'EUR',
|
|
pending: false,
|
|
);
|
|
const olderBooked = BankTransaction(
|
|
date: '2026-08-01',
|
|
description: 'SALARIS',
|
|
amount: 2000,
|
|
currency: 'EUR',
|
|
pending: false,
|
|
);
|
|
|
|
final merged = mergeApiTransactionsWithCache(
|
|
[settled],
|
|
[stalePending, olderBooked],
|
|
);
|
|
|
|
expect(merged, hasLength(2));
|
|
expect(merged.any((tx) => tx.pending), isFalse);
|
|
expect(merged.any((tx) => tx.description.contains('SALARIS')), isTrue);
|
|
expect(merged.any((tx) => tx.description.contains('AH CAMPUS')), isTrue);
|
|
});
|
|
|
|
test('API merge keeps live pending from the feed', () {
|
|
const livePending = BankTransaction(
|
|
date: '2026-09-10',
|
|
description: 'PENDING COFFEE',
|
|
amount: -4.0,
|
|
currency: 'EUR',
|
|
pending: true,
|
|
);
|
|
final merged = mergeApiTransactionsWithCache([livePending], const []);
|
|
expect(merged, hasLength(1));
|
|
expect(merged.single.pending, isTrue);
|
|
});
|
|
|
|
test('dropSettledPendingDuplicates removes pending twin of booked', () {
|
|
const pending = BankTransaction(
|
|
date: '2026-09-01',
|
|
description: 'AH CAMPUS DIEMEN',
|
|
amount: -12.5,
|
|
currency: 'EUR',
|
|
pending: true,
|
|
);
|
|
const booked = BankTransaction(
|
|
date: '2026-09-02',
|
|
description: 'BCK*AH CAMPUS DIEMEN ZUID',
|
|
amount: -12.5,
|
|
currency: 'EUR',
|
|
pending: false,
|
|
);
|
|
final cleaned = dropSettledPendingDuplicates([pending, booked]);
|
|
expect(cleaned, hasLength(1));
|
|
expect(cleaned.single.pending, isFalse);
|
|
});
|
|
}
|