Skip to content

Commit 4d89cfe

Browse files
authored
Modify Consorbank PDF-Importer to support new transaction (#5217)
Closes #5216 https://forum.portfolio-performance.info/t/pdf-import-von-consorsbank/2697/334
1 parent 0c8161b commit 4d89cfe

File tree

3 files changed

+188
-74
lines changed

3 files changed

+188
-74
lines changed

name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/ConsorsbankPDFExtractorTest.java

Lines changed: 77 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package name.abuchen.portfolio.datatransfer.pdf.consorsbank;
22

3-
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.check;
43
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.deposit;
54
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.dividend;
65
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasAmount;
@@ -4016,14 +4015,7 @@ public void testDividende19WithSecurityInEUR()
40164015
hasSource("Dividende19.txt"), //
40174016
hasNote(null), //
40184017
hasAmount("EUR", 44.78), hasGrossValue("EUR", 60.15), //
4019-
hasTaxes("EUR", 9.02 + 6.02 + 0.33), hasFees("EUR", 0.00), //
4020-
check(tx -> {
4021-
var c = new CheckCurrenciesAction();
4022-
var account = new Account();
4023-
account.setCurrencyCode("EUR");
4024-
var s = c.process((AccountTransaction) tx, account);
4025-
assertThat(s, is(Status.OK_STATUS));
4026-
}))));
4018+
hasTaxes("EUR", 9.02 + 6.02 + 0.33), hasFees("EUR", 0.00))));
40274019
}
40284020

40294021
@Test
@@ -4157,14 +4149,7 @@ public void testDividende22WithSecurityInEUR()
41574149
hasSource("Dividende22.txt"), //
41584150
hasNote(null), //
41594151
hasAmount("EUR", 56.33), hasGrossValue("EUR", 56.33), //
4160-
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00), //
4161-
check(tx -> {
4162-
var c = new CheckCurrenciesAction();
4163-
var account = new Account();
4164-
account.setCurrencyCode("EUR");
4165-
var s = c.process((AccountTransaction) tx, account);
4166-
assertThat(s, is(Status.OK_STATUS));
4167-
}))));
4152+
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00))));
41684153
}
41694154

41704155
@Test
@@ -4232,14 +4217,7 @@ public void testDividende23WithSecurityInEUR()
42324217
hasSource("Dividende23.txt"), //
42334218
hasNote(null), //
42344219
hasAmount("EUR", 1.44), hasGrossValue("EUR", 1.94), //
4235-
hasTaxes("EUR", 0.29 + 0.19 + 0.01 + 0.01), hasFees("EUR", 0.00), //
4236-
check(tx -> {
4237-
var c = new CheckCurrenciesAction();
4238-
var account = new Account();
4239-
account.setCurrencyCode("EUR");
4240-
var s = c.process((AccountTransaction) tx, account);
4241-
assertThat(s, is(Status.OK_STATUS));
4242-
}))));
4220+
hasTaxes("EUR", 0.29 + 0.19 + 0.01 + 0.01), hasFees("EUR", 0.00))));
42434221
}
42444222

42454223
@Test
@@ -4307,14 +4285,7 @@ public void testDividende24WithSecurityInEUR()
43074285
hasSource("Dividende24.txt"), //
43084286
hasNote(null), //
43094287
hasAmount("EUR", 10.38), hasGrossValue("EUR", 12.22), //
4310-
hasTaxes("EUR", 1.84), hasFees("EUR", 0.00), //
4311-
check(tx -> {
4312-
var c = new CheckCurrenciesAction();
4313-
var account = new Account();
4314-
account.setCurrencyCode("EUR");
4315-
var s = c.process((AccountTransaction) tx, account);
4316-
assertThat(s, is(Status.OK_STATUS));
4317-
}))));
4288+
hasTaxes("EUR", 1.84), hasFees("EUR", 0.00))));
43184289
}
43194290

43204291
@Test
@@ -4382,14 +4353,7 @@ public void testDividende25WithSecurityInEUR()
43824353
hasSource("Dividende25.txt"), //
43834354
hasNote(null), //
43844355
hasAmount("EUR", 41.99), hasGrossValue("EUR", 41.99), //
4385-
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00), //
4386-
check(tx -> {
4387-
var c = new CheckCurrenciesAction();
4388-
var account = new Account();
4389-
account.setCurrencyCode("EUR");
4390-
var s = c.process((AccountTransaction) tx, account);
4391-
assertThat(s, is(Status.OK_STATUS));
4392-
}))));
4356+
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00))));
43934357
}
43944358

43954359
@Test
@@ -4457,14 +4421,7 @@ public void testDividende26WithSecurityInEUR()
44574421
hasSource("Dividende26.txt"), //
44584422
hasNote(null), //
44594423
hasAmount("EUR", 70.84), hasGrossValue("EUR", 96.21), //
4460-
hasTaxes("EUR", 24.05 + 1.32), hasFees("EUR", 0.00), //
4461-
check(tx -> {
4462-
var c = new CheckCurrenciesAction();
4463-
var account = new Account();
4464-
account.setCurrencyCode("EUR");
4465-
var s = c.process((AccountTransaction) tx, account);
4466-
assertThat(s, is(Status.OK_STATUS));
4467-
}))));
4424+
hasTaxes("EUR", 24.05 + 1.32), hasFees("EUR", 0.00))));
44684425
}
44694426

44704427
@Test
@@ -4532,14 +4489,7 @@ public void testDividende27WithSecurityInEUR()
45324489
hasSource("Dividende27.txt"), //
45334490
hasNote(null), //
45344491
hasAmount("EUR", 69.68), hasGrossValue("EUR", 69.68), //
4535-
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00), //
4536-
check(tx -> {
4537-
var c = new CheckCurrenciesAction();
4538-
var account = new Account();
4539-
account.setCurrencyCode("EUR");
4540-
var s = c.process((AccountTransaction) tx, account);
4541-
assertThat(s, is(Status.OK_STATUS));
4542-
}))));
4492+
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00))));
45434493
}
45444494

45454495
@Test
@@ -4607,14 +4557,7 @@ public void testDividende28WithSecurityInEUR()
46074557
hasSource("Dividende28.txt"), //
46084558
hasNote(null), //
46094559
hasAmount("EUR", 9.75), hasGrossValue("EUR", 11.47), //
4610-
hasTaxes("EUR", 1.72), hasFees("EUR", 0.00), //
4611-
check(tx -> {
4612-
var c = new CheckCurrenciesAction();
4613-
var account = new Account();
4614-
account.setCurrencyCode("EUR");
4615-
var s = c.process((AccountTransaction) tx, account);
4616-
assertThat(s, is(Status.OK_STATUS));
4617-
}))));
4560+
hasTaxes("EUR", 1.72), hasFees("EUR", 0.00))));
46184561
}
46194562

46204563
@Test
@@ -4682,14 +4625,75 @@ public void testDividende29WithSecurityInEUR()
46824625
hasSource("Dividende29.txt"), //
46834626
hasNote(null), //
46844627
hasAmount("EUR", 1.81), hasGrossValue("EUR", 2.13), //
4685-
hasTaxes("EUR", 0.32), hasFees("EUR", 0.00), //
4686-
check(tx -> {
4687-
var c = new CheckCurrenciesAction();
4688-
var account = new Account();
4689-
account.setCurrencyCode("EUR");
4690-
var s = c.process((AccountTransaction) tx, account);
4691-
assertThat(s, is(Status.OK_STATUS));
4692-
}))));
4628+
hasTaxes("EUR", 0.32), hasFees("EUR", 0.00))));
4629+
}
4630+
4631+
@Test
4632+
public void testDividende30()
4633+
{
4634+
var extractor = new ConsorsbankPDFExtractor(new Client());
4635+
4636+
List<Exception> errors = new ArrayList<>();
4637+
4638+
var results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Dividende30.txt"), errors);
4639+
4640+
assertThat(errors, empty());
4641+
assertThat(countSecurities(results), is(1L));
4642+
assertThat(countBuySell(results), is(0L));
4643+
assertThat(countAccountTransactions(results), is(1L));
4644+
assertThat(countAccountTransfers(results), is(0L));
4645+
assertThat(countItemsWithFailureMessage(results), is(0L));
4646+
assertThat(results.size(), is(2));
4647+
new AssertImportActions().check(results, "USD");
4648+
4649+
// check security
4650+
assertThat(results, hasItem(security( //
4651+
hasIsin("US7427181091"), hasWkn("852062"), hasTicker(null), //
4652+
hasName("PROCTER & GAMBLE CO., THE Registered Shares o.N."), //
4653+
hasCurrencyCode("USD"))));
4654+
4655+
// check dividends transaction
4656+
assertThat(results, hasItem(dividend( //
4657+
hasDate("2025-11-17T00:00"), hasShares(100.00), //
4658+
hasSource("Dividende30.txt"), //
4659+
hasNote(null), //
4660+
hasAmount("USD", 78.68), hasGrossValue("USD", 105.68), //
4661+
hasTaxes("USD", 27.00), hasFees("USD", 0.00))));
4662+
}
4663+
4664+
@Test
4665+
public void testDividende30WithSecurityInEUR()
4666+
{
4667+
var security = new Security("PROCTER & GAMBLE CO., THE Registered Shares o.N.", "EUR");
4668+
security.setIsin("US7427181091");
4669+
security.setWkn("852062");
4670+
4671+
var client = new Client();
4672+
client.addSecurity(security);
4673+
4674+
var extractor = new ConsorsbankPDFExtractor(client);
4675+
4676+
List<Exception> errors = new ArrayList<>();
4677+
4678+
var results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Dividende30.txt"), errors);
4679+
4680+
assertThat(errors, empty());
4681+
assertThat(countSecurities(results), is(0L));
4682+
assertThat(countBuySell(results), is(0L));
4683+
assertThat(countAccountTransactions(results), is(1L));
4684+
assertThat(countAccountTransfers(results), is(0L));
4685+
assertThat(countItemsWithFailureMessage(results), is(0L));
4686+
assertThat(results.size(), is(1));
4687+
new AssertImportActions().check(results, "USD");
4688+
4689+
// check dividends transaction
4690+
assertThat(results, hasItem(dividend( //
4691+
hasDate("2025-11-17T00:00"), hasShares(100.00), //
4692+
hasSource("Dividende30.txt"), //
4693+
hasNote(null), //
4694+
hasAmount("USD", 78.68), hasGrossValue("USD", 105.68), //
4695+
hasForexGrossValue("EUR", 90.99), //
4696+
hasTaxes("USD", 27.00), hasFees("USD", 0.00))));
46934697
}
46944698

46954699
@Test
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
PDFBox Version: 3.0.5
2+
Portfolio Performance Version: 0.80.4
3+
System: macosx | x86_64 | 21.0.5+11-LTS | Azul Systems, Inc.
4+
-----------------------------------------
5+
Consorsbank • 90318 Nürnberg
6+
Depotnummer: 4696448174
7+
1500561976/00
8+
Vermerk der Bank: 1000
9+
2
10+
nhDv-LeWUjfS BfPwB
11+
Datum: 18.11.2025
12+
KsY-mhJiRIfL-RiBZZ 55
13+
Seite: 1 von 2
14+
13300 iFXohyJfhLHK
15+
Dividendengutschrift
16+
Wertpapierbezeichnung WKN ISIN
17+
PROCTER & GAMBLE CO., THE Registered Shares o.N. 852062 US7427181091
18+
Bestand
19+
100 Stück
20+
Dividende pro Stück 1,0568 USD Schlusstag 23.10.2025
21+
Brutto in USD 105,68 USD
22+
abzgl. Quellensteuer 15,00 % von 105,68 USD 15,85 USD
23+
89,83 USD
24+
Zwischensumme in USD
25+
Devisenkurs 1,161500 USD / EUR
26+
90,99 EUR
27+
Brutto in EUR
28+
13,65 EUR
29+
Quellensteuer in EUR
30+
Zwischensumme in EUR 77,34 EUR
31+
abzgl. Kapitalertragsteuer 25,00 % von 36,39 EUR 9,10 EUR
32+
abzgl. Solidaritätszuschlag 5,50 % von 9,10 EUR 0,50 EUR
33+
67,74 EUR
34+
Netto in EUR
35+
78,68 USD
36+
Netto in USD zugunsten IBAN qx55 4648 3025 8585 7395 06
37+
Valuta 17.11.2025 BIC DABBDEMMXXX
38+
Anrechenbare Quellensteuer EUR
39+
15,00 % von 105,68 USD 13,65
40+
Bitte beachten Sie die weiteren Informationen auf Seite 2.
41+
Consorsbank ist eine eingetragene Marke der BNP Paribas S.A. Niederlassung Deutschland (AG nach franz. Recht).
42+
Standort Nürnberg: Bahnhofstraße 55, 90402 Nürnberg, HRB Nürnberg 31129, USt-IdNr. DE191528929
43+
Fon +49 (0) 911 / 369-30 00, Fax +49 (0) 911 / 369-10 00, [email protected], www.consorsbank.de
44+
Sitz der BNP Paribas S.A.: 16, boulevard des Italiens, 75009 Paris, Frankreich, Registergericht: R.C.S. Paris 662 042 449
45+
Président du Conseil d‘Administration (Präsident des Verwaltungsrates): Jean Lemierre, Directeur Général (Generaldirektor): Jean-Laurent Bonnafé
46+
C123A1EC-13A0-5133-19D2-6F17D5970C23
47+
Depotnummer: 0408762232
48+
1500561976/00
49+
Vermerk der Bank: 1000
50+
2
51+
Datum: 18.11.2025
52+
Seite: 2 von 2
53+
Details zur Abrechnung
54+
Steuerpflichtiger Gesamtertrag 90,99 EUR
55+
Mit Verrechnungstopf "Allgemein" verrechnet 0,00 EUR
56+
Mit Sparerpauschbetrag verrechnet 0,00 EUR
57+
Mit Quellensteuer verrechnet -54,60 EUR
58+
somit verrechnete Quellensteuer -13,65 EUR
59+
Bemessungsgrundlage für Kapitalertragsteuer gesamt 36,39 EUR
60+
Details zu den Verrechnungstöpfen
61+
Verrechnungstopf "Allgemein" vor der Abrechnung 0,00 EUR
62+
Mit Verrechnungstopf "Allgemein" verrechnet 0,00 EUR
63+
Verrechnungstopf "Allgemein" nach der Abrechnung 0,00 EUR
64+
Sparerpauschbetrag vor der Abrechnung 0,00 EUR
65+
Mit Sparerpauschbetrag verrechnet 0,00 EUR
66+
Sparerpauschbetrag nach der Abrechnung 0,00 EUR
67+
Verrechnungstopf "Quellensteuer" vor der Abrechnung 0,00 EUR
68+
Änderung Verrechnungstopf "Quellensteuer" 0,00 EUR
69+
Verrechnungstopf "Quellensteuer" nach der Abrechnung 0,00 EUR

name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ConsorsbankPDFExtractor.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,11 +490,35 @@ private void addDividendeTransaction()
490490
}),
491491
// @formatter:off
492492
// Netto zugunsten IBAN DE00 0000 0000 0000 0000 00 9,34 EUR
493+
// @formatter:on
494+
section -> section //
495+
.attributes("amount", "currency") //
496+
.match("^Netto (zugunsten|zulasten) .* (?<amount>[\\.,\\d]+) (?<currency>[A-Z]{3})$") //
497+
.assign((t, v) -> {
498+
t.setCurrencyCode(asCurrencyCode(v.get("currency")));
499+
t.setAmount(asAmount(v.get("amount")));
500+
}),
501+
// @formatter:off
493502
// Netto in USD zugunsten IBAN DE12 3456 3456 3456 3456 78 6,46 USD
494503
// @formatter:on
495504
section -> section //
496505
.attributes("amount", "currency") //
497-
.match("^Netto( in [A-Z]{3})? (zugunsten|zulasten) .* (?<amount>[\\.,\\d]+) (?<currency>[A-Z]{3})$") //
506+
.match("^Netto in [A-Z]{3} (zugunsten|zulasten) .* (?<amount>[\\.,\\d]+) (?<currency>[A-Z]{3})$") //
507+
.assign((t, v) -> {
508+
t.setCurrencyCode(asCurrencyCode(v.get("currency")));
509+
t.setAmount(asAmount(v.get("amount")));
510+
}),
511+
// @formatter:off
512+
// 67,74 EUR
513+
// Netto in EUR
514+
// 78,68 USD
515+
// Netto in USD zugunsten IBAN qx55 4648 3025 8585 7395 06
516+
// @formatter:on
517+
section -> section //
518+
.attributes("amount", "currency") //
519+
.find("Netto in [A-Z]{3}") //
520+
.match("^(?<amount>[\\.,\\d]+) (?<currency>[A-Z]{3})$")
521+
.match("^Netto in [A-Z]{3} (zugunsten|zulasten) .*$") //
498522
.assign((t, v) -> {
499523
t.setCurrencyCode(asCurrencyCode(v.get("currency")));
500524
t.setAmount(asAmount(v.get("amount")));
@@ -598,6 +622,23 @@ private void addDividendeTransaction()
598622
checkAndSetGrossUnit(gross, fxGross, t, type.getCurrentContext());
599623
}),
600624
// @formatter:off
625+
// Brutto in USD 105,68 USD
626+
// Devisenkurs 1,161500 USD / EUR
627+
// @formatter:on
628+
section -> section //
629+
.attributes("gross", "exchangeRate", "termCurrency", "baseCurrency") //
630+
.match("^Brutto in [A-Z]{3} (?<gross>[\\.,\\d]+) [A-Z]{3}$") //
631+
.match("^Devisenkurs (?<exchangeRate>[\\.,\\d]+) (?<termCurrency>[A-Z]{3}) \\/ (?<baseCurrency>[A-Z]{3})$") //
632+
.assign((t, v) -> {
633+
var rate = asExchangeRate(v);
634+
type.getCurrentContext().putType(rate);
635+
636+
var gross = Money.of(rate.getTermCurrency(), asAmount(v.get("gross")));
637+
var fxGross = rate.convert(rate.getBaseCurrency(), gross);
638+
639+
checkAndSetGrossUnit(gross, fxGross, t, type.getCurrentContext());
640+
}),
641+
// @formatter:off
601642
// Brutto in USD 10,00 USD
602643
// Devisenkurs 1,12000 USD / EUR
603644
// Brutto in EUR 8,93 EUR

0 commit comments

Comments
 (0)