From bd16cb445fd219d7677c6f647da515fee99b1bcb Mon Sep 17 00:00:00 2001 From: Nirus2000 Date: Sun, 17 Jul 2022 08:52:54 +0200 Subject: [PATCH] Modify Consorbank PDF-Importer to support new transactions https://forum.portfolio-performance.info/t/pdf-import-von-consorsbank/2697/200 https://forum.portfolio-performance.info/t/pdf-import-von-consorsbank/2697/201 --- .../ConsorsbankPDFExtractorTest.java | 153 +++++++++++++ .../pdf/consorsbank/Depotauszug01.txt | 171 ++++++++++++++ .../datatransfer/pdf/consorsbank/Kauf20.txt | 36 +++ .../pdf/ConsorsbankPDFExtractor.java | 216 +++++++++++++----- 4 files changed, 522 insertions(+), 54 deletions(-) create mode 100644 name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/Depotauszug01.txt create mode 100644 name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/Kauf20.txt diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/ConsorsbankPDFExtractorTest.java b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/ConsorsbankPDFExtractorTest.java index a012b3ba7b..9d066cf9ed 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/ConsorsbankPDFExtractorTest.java +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/ConsorsbankPDFExtractorTest.java @@ -7,10 +7,12 @@ import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import org.junit.Test; +import name.abuchen.portfolio.datatransfer.Extractor; import name.abuchen.portfolio.datatransfer.Extractor.BuySellEntryItem; import name.abuchen.portfolio.datatransfer.Extractor.Item; import name.abuchen.portfolio.datatransfer.Extractor.SecurityItem; @@ -1101,6 +1103,49 @@ public void testWertpapierKauf19_PartialExecution2WithSecurityInEUR() assertThat(s, is(Status.OK_STATUS)); } + @Test + public void testWertpapierKauf20() + { + ConsorsbankPDFExtractor extractor = new ConsorsbankPDFExtractor(new Client()); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Kauf20.txt"), errors); + + assertThat(errors, empty()); + assertThat(results.size(), is(2)); + new AssertImportActions().check(results, CurrencyUnit.EUR); + + // check security + Security security = results.stream().filter(SecurityItem.class::isInstance).findFirst() + .orElseThrow(IllegalArgumentException::new).getSecurity(); + assertThat(security.getIsin(), is("DE000A2AA402")); + assertThat(security.getWkn(), is("A2AA40")); + assertThat(security.getName(), is("CLERE AG O.N.")); + assertThat(security.getCurrencyCode(), is(CurrencyUnit.EUR)); + + // check buy sell transaction + BuySellEntry entry = (BuySellEntry) results.stream().filter(BuySellEntryItem.class::isInstance).findFirst() + .orElseThrow(IllegalArgumentException::new).getSubject(); + + assertThat(entry.getPortfolioTransaction().getType(), is(PortfolioTransaction.Type.BUY)); + assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.BUY)); + + assertThat(entry.getPortfolioTransaction().getDateTime(), is(LocalDateTime.parse("2019-09-06T13:43:10"))); + assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(300))); + assertThat(entry.getSource(), is("Kauf20.txt")); + assertThat(entry.getNote(), is("Limitkurs 11,300000 EUR")); + + assertThat(entry.getPortfolioTransaction().getMonetaryAmount(), + is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(3408.64)))); + assertThat(entry.getPortfolioTransaction().getGrossValue(), + is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(3390.00)))); + assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.TAX), + is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.00)))); + assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.FEE), + is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(2.50 + 2.71 + 8.48 + 4.95)))); + } + @Test public void testWertpapierBezug01() { @@ -2998,4 +3043,112 @@ public void testNachtraeglicheVerlustverrechnung02() assertThat(transaction.getUnitSum(Unit.Type.FEE), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.00)))); } + + @Test + public void testDepotauszug01() + { + ConsorsbankPDFExtractor extractor = new ConsorsbankPDFExtractor(new Client()); + + List errors = new ArrayList(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Depotauszug01.txt"), errors); + + assertThat(errors, empty()); + assertThat(results.size(), is(9)); + + // check transaction + // get transactions + Iterator iter = results.stream().filter(TransactionItem.class::isInstance).iterator(); + assertThat(results.stream().filter(i -> i instanceof TransactionItem).count(), is(9L)); + + Item item = iter.next(); + + // assert transaction + AccountTransaction transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.DEPOSIT)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-08-21T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(6500.00)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("Gutschrift puts")); + + item = iter.next(); + + // assert transaction + transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.DEPOSIT)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-08-22T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(5500.00)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("Gutschrift google 2")); + + item = iter.next(); + + // assert transaction + transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.DEPOSIT)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-08-22T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(757.00)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("Gutschrift google 4")); + + item = iter.next(); + + // assert transaction + transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.DEPOSIT)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-08-22T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(10000.00)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("Gutschrift balance trades")); + + item = iter.next(); + + // assert transaction + transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.DEPOSIT)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-08-22T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(2800.00)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("Gutschrift google 3")); + + item = iter.next(); + + // assert transaction + transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.DEPOSIT)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-08-31T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(2358.20)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("Gutschrift trade put")); + + item = iter.next(); + + // assert transaction + transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.DEPOSIT)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-09-03T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(4900.00)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("D-Gutschrift")); + + item = iter.next(); + + // assert transaction + transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.REMOVAL)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-08-21T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(25308.00)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("Überweisung sidelines")); + + item = iter.next(); + + // assert transaction + transaction = (AccountTransaction) item.getSubject(); + assertThat(transaction.getType(), is(AccountTransaction.Type.REMOVAL)); + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2012-08-23T00:00"))); + assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(12358.00)))); + assertThat(transaction.getSource(), is("Depotauszug01.txt")); + assertThat(transaction.getNote(), is("Überweisung saving")); + } } diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/Depotauszug01.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/Depotauszug01.txt new file mode 100644 index 0000000000..2eccb5fc17 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/Depotauszug01.txt @@ -0,0 +1,171 @@ +PDFBox Version: 1.8.16 +----------------------------------------- +Cortal Consors • 90318 Nürnberg Kontonummer 0820011111 +Kontotyp Verrechnungskonto +1108011111/00 +Kontoinhaber Max Mustermann +Max Mustermann +Musterstr. 77 +44144 Stadt Vermerk der Bank 1000 +00 +1108011111/00 +Soll Haben +Saldo alt +57,46+ +Saldo neu +6.017,26+ +Valutarischer Saldo +7.258,72+ +Kontoauszug 5 Konto-Nr. 0820 011 111 Blatt 1 +Datum 03.09.12 Bankleitzahl 760 300 80 Kontowährung EUR +BIC (für EUR) CSDBDE71XXX BIC GENODEFFXXX +IBAN DE03760300800820011111 (Alle Währungen außer EUR) +Text/Verwendungszweck Datum PNNr Wert Soll Haben +UEBERWEISUNG NR.99999999991 21.08. 8401 21.08. 25.308,00- + Max Mustermann + < 760 300 80 > 820022222 sidelines +GUTSCHRIFT NR.99999999992 21.08. 8401 21.08. 6.500,00+ + Mustermann,Max + < 760 300 80 > 820022222 puts +*** VALUTARISCHER SALDO PER 21.08. *** 18.750,54- +EFFEKTEN NR.0000000000011 21.08. 8808 23.08. 13.166,19+ + WP-ABRECHNUNG 0000000000011 + Verkauf WKN: 659990 + MERCK KGAA O.N. +EFFEKTEN NR.0000000000111 21.08. 8808 23.08. 6.349,12+ + WP-ABRECHNUNG 0000000000111 + Verkauf WKN: 803200 + COMMERZBANK AG O.N. +EFFEKTEN NR.0000000001111 21.08. 8808 23.08. 5.735,42+ + WP-ABRECHNUNG 0000000001111 + Verkauf WKN: 823212 + LUFTHANSA AG VNA O.N. +Hinweis für Kontoauszüge, Wertpapierabrechnungen und Depotbuchungsanzeigen: +Kapitalerträge und Spekulationsgewinne sind einkommensteuerpflichtig. +Einwendungen wegen Unrichtigkeit oder Unvollständigkeit dieser Mitteilung oder die Nichtgenehmigung einer im Wege der Einzugsermächtigung erfolgten +Lastschriftabbuchung müssen unverzüglich erhoben werden, vgl. Nummer B. Ziffer I. 11 (4) und (5) der Allgemeine Geschäftsbedingungen (AGB Banken) sowie +unter B. VII. Ziffer 2.4 der Lastschriftbedingungen. Umsätze und Kontobuchungen, die nach dem Erstellungsdatum anfallen und sich auf den Abrechnungssaldo des +abgelaufenen Abrechnungszeitraumes auswirken, werden erst mit dem folgenden Kontoauszug ausgewiesen. Korrekturen werden seitens der Bank gekennzeichnet. +Machen Sie Ihre Einwendungen in Textform geltend, genügt die Absendung innerhalb der Sechs-Wochen-Frist an Cortal Consors Deutschland (Revision) oder per +Fax oder Mail an die unten angegebenen Adressen. Das Unterlassen rechtzeitiger Einwendungen gilt als Genehmigung. +Cortal Consors S.A. Zweigniederlassung Deutschland +Bahnhofstraße 55, 90402 Nürnberg, HR Nürnberg B20075, USt-IdNr. DE225900761, info@cortalconsors.de, www.cortalconsors.de +Fon +49 (0) 911 / 369-30 00, Fax +49 (0) 911 / 369-10 00 +Sitz der Cortal Consors S.A.: 1, boulevard Haussmann, 75318 Paris CEDEX 09, Frankreich, Registergericht: R.C.S. Paris 327 787 909 +Président du Conseil d’Administration (Verwaltungsratsvorsitzender) und Directeur Général (Generaldirektor) der Cortal Consors S.A.: Olivier Le Grand +Leitung der Zweigniederlassung Deutschland: Kai Friedrich (CEO), Richard Döppmann +Kontoauszug 5 Konto-Nr. 0820 011 111 Blatt 2 +Datum 03.09.12 Bankleitzahl 760 300 80 Kontowährung EUR +BIC (für EUR) CSDBDE71XXX BIC GENODEFFXXX +IBAN DE03760300800820011111 (Alle Währungen außer EUR) +Text/Verwendungszweck Datum PNNr Wert Soll Haben +*** VALUTARISCHER SALDO PER 23.08. *** 13.199,19+ +GUTSCHRIFT NR.99999999993 22.08. 8401 22.08. 5.500,00+ + Mustermann,Max + < 760 300 80 > 820022222 google 2 +GUTSCHRIFT NR.99999999994 22.08. 8401 22.08. 757,00+ + Mustermann,Max + < 760 300 80 > 820022222 google 4 +GUTSCHRIFT NR.99999999995 22.08. 8401 22.08. 10.000,00+ + Mustermann,Max + < 760 300 80 > 820022222 balance trades +GUTSCHRIFT NR.99999999996 22.08. 8401 22.08. 2.800,00+ + Mustermann,Max + < 760 300 80 > 820022222 google 3 +*** VALUTARISCHER SALDO PER 22.08. *** 306,46+ +EFFEKTEN NR.0000000000001 22.08. 8808 24.08. 6.080,10- + WP-ABRECHNUNG 0000000000001 + Kauf WKN: DE4FY1 + DEUT.BANK PUT13 DAX +*** VALUTARISCHER SALDO PER 24.08. *** 7.119,09+ +UEBERWEISUNG NR.99999999997 23.08. 8401 23.08. 12.358,00- + Max Mustermann + < 760 300 80 > 820022222 saving +*** VALUTARISCHER SALDO PER 23.08. *** 13.199,19+ +EFFEKTEN 23.08. 8808 27.08. 253,90- + WP-ABRECHNUNG 0000000111115 + Kauf WKN: A0B7FY + GOOGLE INC. A DL -,001 +EFFEKTEN 23.08. 8808 27.08. 438,93- + WP-ABRECHNUNG 0000000111113 + Kauf WKN: A0B7FY + GOOGLE INC. A DL -,001 +EFFEKTEN 23.08. 8808 27.08. 800,48- + WP-ABRECHNUNG 0000000111117 + Kauf WKN: A0B7FY + GOOGLE INC. A DL -,001 +EFFEKTEN 23.08. 8808 27.08. 1.015,59- + WP-ABRECHNUNG 0000000111114 + Kauf WKN: A0B7FY + GOOGLE INC. A DL -,001 +Hinweis für Kontoauszüge, Wertpapierabrechnungen und Depotbuchungsanzeigen: +Kapitalerträge und Spekulationsgewinne sind einkommensteuerpflichtig. +Einwendungen wegen Unrichtigkeit oder Unvollständigkeit dieser Mitteilung oder die Nichtgenehmigung einer im Wege der Einzugsermächtigung erfolgten +Lastschriftabbuchung müssen unverzüglich erhoben werden, vgl. Nummer B. Ziffer I. 11 (4) und (5) der Allgemeine Geschäftsbedingungen (AGB Banken) sowie +unter B. VII. Ziffer 2.4 der Lastschriftbedingungen. Umsätze und Kontobuchungen, die nach dem Erstellungsdatum anfallen und sich auf den Abrechnungssaldo des +abgelaufenen Abrechnungszeitraumes auswirken, werden erst mit dem folgenden Kontoauszug ausgewiesen. Korrekturen werden seitens der Bank gekennzeichnet. +Machen Sie Ihre Einwendungen in Textform geltend, genügt die Absendung innerhalb der Sechs-Wochen-Frist an Cortal Consors Deutschland (Revision) oder per +Fax oder Mail an die unten angegebenen Adressen. Das Unterlassen rechtzeitiger Einwendungen gilt als Genehmigung. +Cortal Consors S.A. Zweigniederlassung Deutschland +Bahnhofstraße 55, 90402 Nürnberg, HR Nürnberg B20075, USt-IdNr. DE225900761, info@cortalconsors.de, www.cortalconsors.de +Fon +49 (0) 911 / 369-30 00, Fax +49 (0) 911 / 369-10 00 +Sitz der Cortal Consors S.A.: 1, boulevard Haussmann, 75318 Paris CEDEX 09, Frankreich, Registergericht: R.C.S. Paris 327 787 909 +Président du Conseil d’Administration (Verwaltungsratsvorsitzender) und Directeur Général (Generaldirektor) der Cortal Consors S.A.: Olivier Le Grand +Leitung der Zweigniederlassung Deutschland: Kai Friedrich (CEO), Richard Döppmann +Kontoauszug 5 Konto-Nr. 0820 011 111 Blatt 3 +Datum 03.09.12 Bankleitzahl 760 300 80 Kontowährung EUR +BIC (für EUR) CSDBDE71XXX BIC GENODEFFXXX +IBAN DE03760300800820011111 (Alle Währungen außer EUR) +Text/Verwendungszweck Datum PNNr Wert Soll Haben +EFFEKTEN 23.08. 8808 27.08. 1.024,55- + WP-ABRECHNUNG 0000000111112 + Kauf WKN: A0B7FY + GOOGLE INC. A DL -,001 +EFFEKTEN 23.08. 8808 27.08. 1.713,87- + WP-ABRECHNUNG 0000000111111 + Kauf WKN: A0B7FY + GOOGLE INC. A DL -,001 +EFFEKTEN 23.08. 8808 27.08. 1.871,25- + WP-ABRECHNUNG 0000000111116 + Kauf WKN: A0B7FY + GOOGLE INC. A DL -,001 +*** VALUTARISCHER SALDO PER 27.08. *** 0,52+ +GUTSCHRIFT NR.99999999998 31.08. 8401 31.08. 2.358,20+ + Mustermann,Max + < 760 300 80 > 820022222 trade put +*** VALUTARISCHER SALDO PER 31.08. *** 2.358,72+ +EFFEKTEN NR.0000001111111 31.08. 8808 04.09. 6.140,25- + WP-ABRECHNUNG 0000001111111 + Kauf WKN: DE4FY1 + DEUT.BANK PUT13 DAX +EFFEKTEN NR.0000011111112 31.08. 8808 04.09. 7.175,83- + WP-ABRECHNUNG 0000011111112 + Kauf WKN: DE4FY1 + DEUT.BANK PUT13 DAX +EFFEKTEN NR.0000111111111 31.08. 8808 04.09. 6.094,57+ + WP-ABRECHNUNG 0000111111111 + Verkauf WKN: DE4FY1 + DEUT.BANK PUT13 DAX +EFFEKTEN NR.0000111111112 31.08. 8808 04.09. 5.980,05+ + WP-ABRECHNUNG 0000111111112 + Verkauf WKN: DE4FY1 + DEUT.BANK PUT13 DAX +*** VALUTARISCHER SALDO PER 04.09. *** 6.017,26+ +D-GUTSCHRIFT NR.99999999999 03.09. 7998 03.09. 4.900,00+ + Mustermann,Max + < 760 300 80 > 820022222 +*** VALUTARISCHER SALDO PER 03.09. *** 7.258,72+ +Hinweis für Kontoauszüge, Wertpapierabrechnungen und Depotbuchungsanzeigen: +Kapitalerträge und Spekulationsgewinne sind einkommensteuerpflichtig. +Einwendungen wegen Unrichtigkeit oder Unvollständigkeit dieser Mitteilung oder die Nichtgenehmigung einer im Wege der Einzugsermächtigung erfolgten +Lastschriftabbuchung müssen unverzüglich erhoben werden, vgl. Nummer B. Ziffer I. 11 (4) und (5) der Allgemeine Geschäftsbedingungen (AGB Banken) sowie +unter B. VII. Ziffer 2.4 der Lastschriftbedingungen. Umsätze und Kontobuchungen, die nach dem Erstellungsdatum anfallen und sich auf den Abrechnungssaldo des +abgelaufenen Abrechnungszeitraumes auswirken, werden erst mit dem folgenden Kontoauszug ausgewiesen. Korrekturen werden seitens der Bank gekennzeichnet. +Machen Sie Ihre Einwendungen in Textform geltend, genügt die Absendung innerhalb der Sechs-Wochen-Frist an Cortal Consors Deutschland (Revision) oder per +Fax oder Mail an die unten angegebenen Adressen. Das Unterlassen rechtzeitiger Einwendungen gilt als Genehmigung. +Cortal Consors S.A. Zweigniederlassung Deutschland +Bahnhofstraße 55, 90402 Nürnberg, HR Nürnberg B20075, USt-IdNr. DE225900761, info@cortalconsors.de, www.cortalconsors.de +Fon +49 (0) 911 / 369-30 00, Fax +49 (0) 911 / 369-10 00 +Sitz der Cortal Consors S.A.: 1, boulevard Haussmann, 75318 Paris CEDEX 09, Frankreich, Registergericht: R.C.S. Paris 327 787 909 +Président du Conseil d’Administration (Verwaltungsratsvorsitzender) und Directeur Général (Generaldirektor) der Cortal Consors S.A.: Olivier Le Grand +Leitung der Zweigniederlassung Deutschland: Kai Friedrich (CEO), Richard Döppmann \ No newline at end of file diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/Kauf20.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/Kauf20.txt new file mode 100644 index 0000000000..9e84bc1612 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/consorsbank/Kauf20.txt @@ -0,0 +1,36 @@ +PDFBox Version: 1.8.16 +----------------------------------------- +Consorsbank • 90318 Nürnberg +Depotnummer 1234567890 +1504753979/00 +Vorname Nachname +Straße Hausnummer +PLZ ORT Vermerk der Bank 200002 +ORDERABRECHNUNG +KAUF AM 06.09.2019 UM 13:43:10 HAMBURG NR. 148553598.001 +Bezeichnung WKN ISIN +CLERE AG O.N. A2AA40 DE000A2AA402 +Einheit Umsatz +ST 300,00000 +Kurs 11,300000 EUR P.ST. +Kurswert EUR 3.390,00 +Börsenplatzgebühr EUR 2,50 +Courtage EUR 2,71 +Provision EUR 8,48 +Grundgebühr EUR 4,95 +Wert 10.09.2019 EUR 3.408,64 +zulasten Konto-Nr. 9876543210 +Bestand zugunsten Girosammelverwahrung +CBF 2126 +Limitkurs 11,300000 EUR +Beratungsfreies Geschäft +Hinweis für Orderabrechnungen und Depotbuchungsanzeigen: +Einwendungen wegen Unrichtigkeit oder Unvollständigkeit dieser Mitteilung müssen unverzüglich erhoben werden, vgl. Nummer B. Ziffer I. 11 (4) und (5) der +Allgemeinen Geschäftsbedingungen (AGB Banken). +Machen Sie Ihre Einwendungen in Textform geltend, genügt die Absendung innerhalb der Sechs-Wochen-Frist an die Consorsbank oder per Fax oder Mail an die +unten angegebenen Adressen. Das Unterlassen rechtzeitiger Einwendungen gilt als Genehmigung. +Consorsbank ist eine eingetragene Marke der BNP Paribas S.A. Niederlassung Deutschland (AG nach franz. Recht). +Standort Nürnberg: Bahnhofstraße 55, 90402 Nürnberg, HRB Nürnberg 31129, USt-IdNr. DE191528929 +Fon +49 (0) 911 / 369-30 00, Fax +49 (0) 911 / 369-10 00, info@consorsbank.de, www.consorsbank.de +Sitz der BNP Paribas S.A.: 16, boulevard des Italiens, 75009 Paris, Frankreich, Registergericht: R.C.S. Paris 662 042 449 +Président du Conseil d‘Administration (Präsident des Verwaltungsrates): Jean Lemierre, Directeur Général (Generaldirektor): Jean-Laurent Bonnafé \ No newline at end of file diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ConsorsbankPDFExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ConsorsbankPDFExtractor.java index f6e6a8c262..440bbbeadc 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ConsorsbankPDFExtractor.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ConsorsbankPDFExtractor.java @@ -3,6 +3,7 @@ import static name.abuchen.portfolio.datatransfer.pdf.PDFExtractorUtils.checkAndSetGrossUnit; import static name.abuchen.portfolio.util.TextUtil.trim; +import java.util.Map; import java.util.function.BiConsumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -49,6 +50,7 @@ public ConsorsbankPDFExtractor(Client client) addEncashmentTransaction(); addAdvanceTaxTransaction(); addTaxAdjustmentTransaction(); + addDepotStatementTransaction(); } @Override @@ -223,31 +225,33 @@ private void addBuySellTransaction() // Kurswert USD 540,00 // umger. zum Devisenkurs USD 1,077900 EUR 500,97 // UMGER. ZUM DEVISENKURS USD 0,882100 EUR 56,68 - section -> section.attributes("fxCurrency", "fxGross", "gross", "exchangeRate", "baseCurrency", "termCurrency") + section -> section + .attributes("fxCurrency", "fxGross", "gross", "exchangeRate", "baseCurrency", "termCurrency") .match("^Kurswert (?[\\w]{3}) (?[\\.,\\d]+)$") .match("^([\\s]+)?(umger\\. zum Devisenkurs|UMGER\\. ZUM DEVISENKURS) ([\\s]+)?(?[\\w]{3}) ([\\s]+)?(?[\\.,\\d]+) ([\\s]+)?(?[\\w]{3}) ([\\s]+)?(?[\\.,\\d]+)$") .assign((t, v) -> { type.getCurrentContext().putType(asExchangeRate(v)); - + Money gross = Money.of(asCurrencyCode(v.get("baseCurrency")), asAmount(v.get("gross"))); Money fxGross = Money.of(asCurrencyCode(v.get("fxCurrency")), asAmount(v.get("fxGross"))); - + checkAndSetGrossUnit(gross, fxGross, t, type); }) , // Kurswert 343,75 USD // Kurswert in EUR 292,80 EUR // Devisenkurs 1,174000 EUR / USD - section -> section.attributes("fxGross", "fxCurrency", "gross", "currency", "baseCurrency", "termCurrency", "exchangeRate") + section -> section + .attributes("fxGross", "fxCurrency", "gross", "currency", "baseCurrency", "termCurrency", "exchangeRate") .match("^Kurswert (?[\\.,\\d]+) (?[\\w]{3})$") .match("^Kurswert in [\\w]{3} (?[\\.,\\d]+) (?[\\w]{3})$") .match("^Devisenkurs (?[\\.,\\d]+) (?[\\w]{3}) \\/ (?[\\w]{3})$") .assign((t, v) -> { type.getCurrentContext().putType(asExchangeRate(v)); - + Money gross = Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("gross"))); Money fxGross = Money.of(asCurrencyCode(v.get("fxCurrency")), asAmount(v.get("fxGross"))); - + checkAndSetGrossUnit(gross, fxGross, t, type); }) , @@ -255,16 +259,17 @@ private void addBuySellTransaction() // Börsenplatzgebühr 7.760,00 JPY // Devisenkurs 141,090000 EUR / JPY // Zwischensumme 7.284,43 EUR - section -> section.attributes("fxGross", "fxCurrency", "baseCurrency", "termCurrency", "exchangeRate") + section -> section + .attributes("fxGross", "fxCurrency", "baseCurrency", "termCurrency", "exchangeRate") .match("^Kurswert (?[\\.,\\d]+) (?[\\w]{3})$") .match("^Devisenkurs (?[\\.,\\d]+) (?[\\w]{3}) \\/ (?[\\w]{3})$") .assign((t, v) -> { PDFExchangeRate exchangeRate = asExchangeRate(v); type.getCurrentContext().putType(exchangeRate); - + Money fxGross = Money.of(asCurrencyCode(v.get("fxCurrency")), asAmount(v.get("fxGross"))); Money gross = exchangeRate.convert(t.getAccountTransaction().getCurrencyCode(), fxGross); - + checkAndSetGrossUnit(gross, fxGross, t, type); }) ) @@ -377,55 +382,59 @@ private void addDividendeTransaction() }) ) - // BRUTTO USD 180,00 - // UMGER.ZUM DEV.-KURS 1,104300 EUR 138,55 - // KAPST-PFLICHTIGER KAPITALERTRAG EUR 64,08 - .section("termCurrency", "fxGross", "exchangeRate", "baseCurrency", "gross").optional() - .match("^BRUTTO ([\\s]+)?(?[\\w]{3}) ([\\s]+)?(?[\\.,\\d]+).*$") - .match("^UMGER\\.ZUM DEV\\.\\-KURS ([\\s]+)?(?[\\.,\\d]+) ([\\s]+)?[\\w]{3} ([\\s]+)?[\\.,\\d]+.*$") - .match("^KAPST\\-PFLICHTIGER KAPITALERTRAG ([\\s]+)?(?[\\w]{3}) ([\\s]+)?(?[\\.,\\d]+).*$") - .assign((t, v) -> { - type.getCurrentContext().putType(asExchangeRate(v)); - - Money gross = Money.of(asCurrencyCode(v.get("baseCurrency")), asAmount(v.get("gross"))); - Money fxGross = Money.of(asCurrencyCode(v.get("termCurrency")), asAmount(v.get("fxGross"))); - - // flip gross and forex gross amounts if necessary. - // Apparently the tax calculations are always in the - // currency of the customer even if the dividend is - // paid in foreign currency and credited to an - // account in foreign currency - - if (gross.getCurrencyCode().equals(t.getCurrencyCode())) - checkAndSetGrossUnit(gross, fxGross, t, type); - else - checkAndSetGrossUnit(fxGross, gross, t, type); - }) + .optionalOneOf( + // BRUTTO USD 180,00 + // UMGER.ZUM DEV.-KURS 1,104300 EUR 138,55 + // KAPST-PFLICHTIGER KAPITALERTRAG EUR 64,08 + section -> section + .attributes("termCurrency", "fxGross", "exchangeRate", "baseCurrency", "gross") + .match("^BRUTTO ([\\s]+)?(?[\\w]{3}) ([\\s]+)?(?[\\.,\\d]+).*$") + .match("^UMGER\\.ZUM DEV\\.\\-KURS ([\\s]+)?(?[\\.,\\d]+) ([\\s]+)?[\\w]{3} ([\\s]+)?[\\.,\\d]+.*$") + .match("^KAPST\\-PFLICHTIGER KAPITALERTRAG ([\\s]+)?(?[\\w]{3}) ([\\s]+)?(?[\\.,\\d]+).*$") + .assign((t, v) -> { + type.getCurrentContext().putType(asExchangeRate(v)); - // Brutto in USD 15,00 USD - // Devisenkurs 1,195900 USD / EUR - // Brutto in EUR 12,54 EUR - .section("fxGross", "fxCurrency", "exchangeRate", "gross", "currency", "baseCurrency", "termCurrency").optional() - .match("^Brutto in [\\w]{3} (?[\\.,\\d]+) (?[\\w]{3})$") - .match("^Devisenkurs (?[\\.,\\d]+) (?[\\w]{3}) \\/ (?[\\w]{3})$") - .match("^Brutto in [\\w]{3} (?[\\.,\\d]+) (?[\\w]{3})$") - .assign((t, v) -> { - type.getCurrentContext().putType(asExchangeRate(v)); + Money gross = Money.of(asCurrencyCode(v.get("baseCurrency")), asAmount(v.get("gross"))); + Money fxGross = Money.of(asCurrencyCode(v.get("termCurrency")), asAmount(v.get("fxGross"))); + + // flip gross and forex gross amounts if necessary. + // Apparently the tax calculations are always in the + // currency of the customer even if the dividend is + // paid in foreign currency and credited to an + // account in foreign currency + + if (gross.getCurrencyCode().equals(t.getCurrencyCode())) + checkAndSetGrossUnit(gross, fxGross, t, type); + else + checkAndSetGrossUnit(fxGross, gross, t, type); + }) + , + // Brutto in USD 15,00 USD + // Devisenkurs 1,195900 USD / EUR + // Brutto in EUR 12,54 EUR + section -> section + .attributes("fxGross", "fxCurrency", "exchangeRate", "gross", "currency", "baseCurrency", "termCurrency") + .match("^Brutto in [\\w]{3} (?[\\.,\\d]+) (?[\\w]{3})$") + .match("^Devisenkurs (?[\\.,\\d]+) (?[\\w]{3}) \\/ (?[\\w]{3})$") + .match("^Brutto in [\\w]{3} (?[\\.,\\d]+) (?[\\w]{3})$") + .assign((t, v) -> { + type.getCurrentContext().putType(asExchangeRate(v)); - Money gross = Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("gross"))); - Money fxGross = Money.of(asCurrencyCode(v.get("fxCurrency")), asAmount(v.get("fxGross"))); + Money gross = Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("gross"))); + Money fxGross = Money.of(asCurrencyCode(v.get("fxCurrency")), asAmount(v.get("fxGross"))); - // flip gross and forex gross amounts if necessary. - // Apparently the tax calculations are always in the - // currency of the customer even if the dividend is - // paid in foreign currency and credited to an - // account in foreign currency + // flip gross and forex gross amounts if necessary. + // Apparently the tax calculations are always in the + // currency of the customer even if the dividend is + // paid in foreign currency and credited to an + // account in foreign currency - if (gross.getCurrencyCode().equals(t.getCurrencyCode())) - checkAndSetGrossUnit(gross, fxGross, t, type); - else - checkAndSetGrossUnit(fxGross, gross, t, type); - }) + if (gross.getCurrencyCode().equals(t.getCurrencyCode())) + checkAndSetGrossUnit(gross, fxGross, t, type); + else + checkAndSetGrossUnit(fxGross, gross, t, type); + }) + ) .conclude(PDFExtractorUtils.fixGrossValueA()) @@ -598,6 +607,100 @@ private void addTaxAdjustmentTransaction() })); } + @SuppressWarnings("nls") + private void addDepotStatementTransaction() + { + final DocumentType type = new DocumentType("Kontoauszug", (context, lines) -> { + Pattern pCurrency = Pattern.compile("^Kontow.hrung (?[\\w]{3})$"); + Pattern pYear = Pattern.compile("^Datum [\\d]{2}\\.[\\d]{2}\\.(?[\\d]{2}) .*$"); + + for (String line : lines) + { + Matcher m = pCurrency.matcher(line); + if (m.matches()) + context.put("currency", m.group("currency")); + + m = pYear.matcher(line); + if (m.matches()) + context.put("year", m.group("year")); + } + }); + this.addDocumentTyp(type); + + Block depositBlock = new Block("^(GUTSCHRIFT|D\\-GUTSCHRIFT) .* [\\d]{2}\\.[\\d]{2}\\. [\\d]+ [\\d]{2}\\.[\\d]{2}\\. [\\.,\\d]+\\+$"); + type.addBlock(depositBlock); + depositBlock.set(new Transaction() + + .subject(() -> { + AccountTransaction t = new AccountTransaction(); + t.setType(AccountTransaction.Type.DEPOSIT); + return t; + }) + + // GUTSCHRIFT NR.99999999992 21.08. 8401 21.08. 6.500,00+ + // < 760 300 80 > 820022222 puts + .section("note1", "date", "amount", "note2") + .match("^(?GUTSCHRIFT|D\\-GUTSCHRIFT) .* [\\d]{2}\\.[\\d]{2}\\. [\\d]+ (?[\\d]{2}\\.[\\d]{2}\\.) (?[\\.,\\d]+)\\+$") + .match("^.* < [\\d\\s]+ > [\\d\\s]+(?.*)$") + .assign((t, v) -> { + Map context = type.getCurrentContext(); + + t.setDateTime(asDate(v.get("date") + context.get("year"))); + t.setCurrencyCode(asCurrencyCode(context.get("currency"))); + t.setAmount(asAmount(v.get("amount"))); + + // Formatting some notes + if (v.get("note1").equals("GUTSCHRIFT")) + v.put("note", "Gutschrift"); + + if (v.get("note1").equals("D-GUTSCHRIFT")) + v.put("note", "D-Gutschrift"); + + t.setNote(trim(v.get("note") + " " + trim(v.get("note2")))); + }) + + .wrap(t -> { + if (t.getCurrencyCode() != null && t.getAmount() != 0) + return new TransactionItem(t); + return null; + })); + + Block removalBlock = new Block("^UEBERWEISUNG .* [\\d]{2}\\.[\\d]{2}\\. [\\d]+ [\\d]{2}\\.[\\d]{2}\\. [\\.,\\d]+\\-$"); + type.addBlock(removalBlock); + removalBlock.set(new Transaction() + + .subject(() -> { + AccountTransaction t = new AccountTransaction(); + t.setType(AccountTransaction.Type.REMOVAL); + return t; + }) + + // UEBERWEISUNG NR.99999999991 21.08. 8401 21.08. 25.308,00- + // < 760 300 80 > 820022222 sidelines + .section("note1", "date", "amount", "note2") + .match("^(?UEBERWEISUNG) .* [\\d]{2}\\.[\\d]{2}\\. [\\d]+ (?[\\d]{2}\\.[\\d]{2}\\.) (?[\\.,\\d]+)\\-$") + .match("^.* < [\\d\\s]+ > [\\d\\s]+(?.*)$") + .assign((t, v) -> { + Map context = type.getCurrentContext(); + + t.setDateTime(asDate(v.get("date") + context.get("year"))); + t.setCurrencyCode(asCurrencyCode(context.get("currency"))); + t.setAmount(asAmount(v.get("amount"))); + + // Formatting some notes + if (v.get("note1").equals("UEBERWEISUNG")) + v.put("note", "Überweisung"); + + t.setNote(trim(v.get("note") + " " + trim(v.get("note2")))); + }) + + .wrap(t -> { + if (t.getCurrencyCode() != null && t.getAmount() != 0) + return new TransactionItem(t); + return null; + })); + } + @SuppressWarnings("nls") private > void addTaxesSectionsTransaction(T transaction, DocumentType type) { @@ -978,6 +1081,11 @@ private > void addFeesSectionsTransaction(T transaction // abzgl. Fremde Spesen 0,07 USD .section("fee", "currency").optional() .match("^(?i)(abzgl\\. )?Fremde Spesen (?[\\.,\\d]+) (?[\\w]{3})$") + .assign((t, v) -> processFeeEntries(t, v, type)) + + // Courtage EUR 2,71 + .section("fee", "currency").optional() + .match("^Courtage (?[\\.,\\d]+) (?[\\w]{3})$") .assign((t, v) -> processFeeEntries(t, v, type)); } } \ No newline at end of file