From db6d2b8a5104bbd99efe356020dc89864ee820f0 Mon Sep 17 00:00:00 2001 From: Nirus2000 Date: Mon, 18 Dec 2023 17:46:33 +0100 Subject: [PATCH] Modify Deutsche Bank PDF-Importer to support new transaction https://forum.portfolio-performance.info/t/pdf-import-von-deutsche-bank/2973/51 --- .../DeutscheBankPDFExtractorTest.java | 63 ++++++++++++++----- .../pdf/deutschebank/Dividende08.txt | 40 ++++++++++++ .../pdf/DeutscheBankPDFExtractor.java | 52 ++++++++++----- 3 files changed, 125 insertions(+), 30 deletions(-) create mode 100644 name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/Dividende08.txt diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankPDFExtractorTest.java b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankPDFExtractorTest.java index b3a59858d0..c174167031 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankPDFExtractorTest.java +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankPDFExtractorTest.java @@ -1,16 +1,5 @@ package name.abuchen.portfolio.datatransfer.pdf.deutschebank; -import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countAccountTransactions; -import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countBuySell; -import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countSecurities; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.IsEmptyCollection.empty; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.check; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.deposit; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.dividend; @@ -32,6 +21,16 @@ import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.removal; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.sale; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.security; +import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countAccountTransactions; +import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countBuySell; +import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countSecurities; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsEmptyCollection.empty; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.text.MessageFormat; import java.time.LocalDateTime; @@ -91,7 +90,8 @@ public void testDividende01() // check dividends transaction assertThat(results, hasItem(dividend( // hasDate("2014-12-15"), hasShares(380), // - hasSource("Dividende01.txt"), hasNote(null), // + hasSource("Dividende01.txt"), // + hasNote(null), // hasAmount("EUR", 64.88), hasGrossValue("EUR", 87.13), hasForexGrossValue("USD", 98.80), // hasTaxes("EUR", 8.71 + 0.47 + 13.07), hasFees("EUR", 0.00)))); } @@ -118,7 +118,8 @@ public void testDividende01WithSecurityInEUR() // check dividends transaction assertThat(results, hasItem(dividend( // hasDate("2014-12-15"), hasShares(380), // - hasSource("Dividende01.txt"), hasNote(null), // + hasSource("Dividende01.txt"), // + hasNote(null), // hasAmount("EUR", 64.88), hasGrossValue("EUR", 87.13), // hasTaxes("EUR", 8.71 + 0.47 + 13.07), hasFees("EUR", 0.00), // check(tx -> { @@ -155,7 +156,8 @@ public void testDividende02() // check dividends transaction assertThat(results, hasItem(dividend( // hasDate("2014-12-15"), hasShares(123), // - hasSource("Dividende02.txt"), hasNote(null), // + hasSource("Dividende02.txt"), // + hasNote(null), // hasAmount("EUR", 14.95), hasGrossValue("EUR", 20.22), // hasTaxes("EUR", 4.28 + 0.23 + 0.76), hasFees("EUR", 0.00)))); } @@ -406,7 +408,7 @@ public void testDividende07() hasName("6% MAGNUM AG GENUßSCHEINE 99/UNBEGR."), // hasCurrencyCode("EUR")))); - // check dividende transaction + // check dividends transaction assertThat(results, hasItem(dividend( // hasDate("2023-09-05T00:00"), hasShares(60.00), // hasSource("Dividende07.txt"), // @@ -415,6 +417,37 @@ public void testDividende07() hasTaxes("EUR", 88.02 + 4.84 + 7.92), hasFees("EUR", 0.00)))); } + @Test + public void testDividende08() + { + DeutscheBankPDFExtractor extractor = new DeutscheBankPDFExtractor(new Client()); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Dividende08.txt"), errors); + + assertThat(errors, empty()); + assertThat(countSecurities(results), is(1L)); + assertThat(countBuySell(results), is(0L)); + assertThat(countAccountTransactions(results), is(1L)); + assertThat(results.size(), is(2)); + new AssertImportActions().check(results, CurrencyUnit.USD); + + // check security + assertThat(results, hasItem(security( // + hasIsin("US1912161007"), hasWkn("850663"), hasTicker(null), // + hasName("COCA-COLA CO., THE REGISTERED SHARES DL -,25"), // + hasCurrencyCode("USD")))); + + // check dividends transaction + assertThat(results, hasItem(dividend( // + hasDate("2023-12-15T00:00"), hasShares(170.00), // + hasSource("Dividende08.txt"), // + hasNote(null), // + hasAmount("USD", 58.22), hasGrossValue("USD", 78.21), // + hasTaxes("USD", 11.74 + 7.82 + 0.43), hasFees("USD", 0.00)))); + } + @Test public void testWertpapierKauf01() { diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/Dividende08.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/Dividende08.txt new file mode 100644 index 0000000000..50d2b73c88 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/Dividende08.txt @@ -0,0 +1,40 @@ +PDFBox Version: 1.8.17 +Portfolio Performance Version: 0.66.2 +----------------------------------------- +Deutsche Bank AG +24/7-Kundenservice (069) 910-10000 +JyehWInT TFKsxmtiY und +EWLZW Dr. hwapgd KngFGdxcT +lmQjgRJRgsER Str. 3 +13210 Usbzsvqhh +18. Dezember 2023 +Ihr Depot Nr. 668 8419216 35 +Dividendengutschrift +Stück WKN ISIN +170,000000 850663 US1912161007 +COCA-COLA CO., THE REGISTERED SHARES DL -,25 +Dividende pro Stück 0,4600000000 USD Zahlbar 15.12.2023 +Ursprungsland USA Ex-Tag 30.11.2023 +Geschäftsjahr 2023 +Bruttoertrag 78,20 USD +15,0000000 % Ausländische Quellensteuer - 11,73 USD +Kapitalertragsteuer (KESt) - 7,82 USD +Solidaritätszuschlag auf KESt - 0,43 USD +Umrechnungskurs USD zu EUR 1,1019000000 +Gutschrift mit Wert 15.12.2023 58,22 USD +Steuerliche Bemessungsgrundlagen zur Dividendengutschrift - keine Steuerbescheinigung +KESt-pflichtiger Kapitalertrag 70,97 EUR +Anrechenbare ausländische Quellensteuer 10,65 EUR +Auf die KESt angerechnete ausländische +10,65 EUR +Quellensteuer +Vorsitzender des Aufsichtsrats: Alexander R. Wynaendts +Vorstand: Christian Sewing (Vorsitzender), James von Moltke, Fabrizio Campelli, Bernd Leukert, Alexander von zur Mühlen, Claudio de Sanctis, Rebecca Short, +Stefan Simon, Olivier Vigneron +Deutsche Bank Aktiengesellschaft mit Sitz in Frankfurt am Main; Amtsgericht Frankfurt am Main, HRB Nr. 30 000; Umsatzsteuer-Id.-Nr. DE114103379; +www.db.com/de, www.deutsche-bank.de 1/2 +TRINCM0001 DIVI 20231216 28176989 +Wir überweisen den Betrag von 58,22 USD auf Ihr Konto 1701689 02. +Kapitalerträge sind einkommensteuerpflichtig! +Diese Mitteilung wurde maschinell erstellt und wird nicht unterschrieben. +2/2 \ No newline at end of file diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/DeutscheBankPDFExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/DeutscheBankPDFExtractor.java index e1288ec417..68e7496ceb 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/DeutscheBankPDFExtractor.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/DeutscheBankPDFExtractor.java @@ -304,22 +304,44 @@ private void addDividendeTransaction() t.setCurrencyCode(asCurrencyCode(v.get("currency"))); }) - // @formatter:off - // Bruttoertrag 98,80 USD 87,13 EUR - // Umrechnungskurs USD zu EUR 1,1339000000 - // @formatter:on - .section("fxGross", "gross", "baseCurrency", "termCurrency", "exchangeRate").optional() // - .match("^Bruttoertrag (?[\\.,\\d]+) [\\w]{3} (?[\\.,\\d]+) [\\w]{3}$") // - .match("^Umrechnungskurs (?[\\w]{3}) zu (?[\\w]{3}) (?[\\.,\\d]+)$") // - .assign((t, v) -> { - ExtrExchangeRate rate = asExchangeRate(v); - type.getCurrentContext().putType(rate); + .optionalOneOf( // + // @formatter:off + // Bruttoertrag 98,80 USD 87,13 EUR + // Umrechnungskurs USD zu EUR 1,1339000000 + // @formatter:on + section -> section // + .attributes("fxGross", "gross", "termCurrency", "baseCurrency", "exchangeRate") // + .match("^Bruttoertrag (?[\\.,\\d]+) [\\w]{3} (?[\\.,\\d]+) [\\w]{3}$") // + .match("^Umrechnungskurs (?[\\w]{3}) zu (?[\\w]{3}) (?[\\.,\\d]+)$") // + .assign((t, v) -> { + ExtrExchangeRate rate = asExchangeRate(v); + type.getCurrentContext().putType(rate); - Money gross = Money.of(rate.getBaseCurrency(), asAmount(v.get("gross"))); - Money fxGross = Money.of(rate.getTermCurrency(), asAmount(v.get("fxGross"))); + Money gross = Money.of(rate.getBaseCurrency(), asAmount(v.get("gross"))); + Money fxGross = Money.of(rate.getTermCurrency(), asAmount(v.get("fxGross"))); - checkAndSetGrossUnit(gross, fxGross, t, type.getCurrentContext()); - }) + checkAndSetGrossUnit(gross, fxGross, t, type.getCurrentContext()); + }), + // @formatter:off + // Bruttoertrag 78,20 USD + // Umrechnungskurs USD zu EUR 1,1019000000 + // @formatter:on + section -> section // + .attributes("gross", "baseCurrency", "termCurrency", "exchangeRate") // + .match("^Bruttoertrag (?[\\.,\\d]+) [\\w]{3}$") // + .match("^Umrechnungskurs (?[\\w]{3}) zu (?[\\w]{3}) (?[\\.,\\d]+)$") // + .assign((t, v) -> { + if (!type.getCurrentContext().getBoolean("negative")) + { + ExtrExchangeRate rate = asExchangeRate(v); + type.getCurrentContext().putType(rate); + + Money gross = Money.of(rate.getBaseCurrency(), asAmount(v.get("gross"))); + Money fxGross = rate.convert(rate.getTermCurrency(), gross); + + checkAndSetGrossUnit(gross, fxGross, t, type.getCurrentContext()); + } + })) .conclude(ExtractorUtils.fixGrossValueA()) @@ -417,7 +439,7 @@ private void addAccountStatementTransaction() // @formatter:on if ("Saldo der Abschlussposten".equals(v.get("note1"))) type.getCurrentContext().putBoolean("skipTransaction", true); - + // @formatter:off // If we have security transaction, then we skip the transaction //