From dcb510720e99ff3c05a018b7facd4da9467424e9 Mon Sep 17 00:00:00 2001 From: Nirus2000 Date: Fri, 6 Oct 2023 04:11:57 +0200 Subject: [PATCH] Modify Vanguard PDF-Importer to support new transaction https://forum.portfolio-performance.info/t/pdf-import-von-vanguard/23084/9 --- .../pdf/vanguardgroupeurope/Dividende02.txt | 80 +++++ .../VanguardGroupEuropePDFExtractorTest.java | 95 ++++- .../pdf/VanguardGroupEuropePDFExtractor.java | 324 ++++++++++-------- 3 files changed, 345 insertions(+), 154 deletions(-) create mode 100644 name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/vanguardgroupeurope/Dividende02.txt diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/vanguardgroupeurope/Dividende02.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/vanguardgroupeurope/Dividende02.txt new file mode 100644 index 0000000000..47c65df0a8 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/vanguardgroupeurope/Dividende02.txt @@ -0,0 +1,80 @@ +PDFBox Version: 1.8.17 +Portfolio Performance Version: 0.65.3 +----------------------------------------- +So erreichen Sie uns: +Web: www.de.vanguard +Telefon: (030) 3119 6465 +E-Mail: kundenservice@vanguard.com +Herr +Max Mustermann +Musterstraße 123 +12345 Musterhausen Außerdem können Sie +uns eine Nachricht aus +dem Postfach Ihres +Benutzerkontos +schreiben. +Bardividende +Portfolio 12345678.001 +Wir teilen Ihnen mit, dass wir die folgenden Erträgnisse unter Eingangsvorbehalt +abgerechnet haben: +Wertpapierbezeichnung FDIX Vanguard S&P 500 UCITS ETF (USD) +Distributing (IE00B3XXRP09) +ISIN IE00B3XXRP09 +Verwahrart Wertpapierrechnung +Lagerland Luxemburg +Nominal/Stück 2,535612 ST +Währung EUR +Original-Ausschüttung USD 0,267572 pro Stück +Wechselkurs 1,066199 +Dividendenart Ordentliche Dividende +Ex-Tag 14.09.2023 +Bruttobetrag EUR 0,64 +Kapitalertragsteuer EUR -0,11 +Solidaritätszuschlag EUR 0,00 +Kirchensteuer EUR 0,00 +Netto-Betrag EUR 0,53 +Ausmachender Betrag EUR 0,53 +Der Abrechnungsbetrag wird mit Valuta 27.9.2023 über Ihr Konto 12345678 gebucht. +Vanguard Group Europe GmbH Postanschrift: Geschäftsführung: Rechtsform: Gesellschaft mit +Kurfürstendamm 21 Kurfürstendamm 21 Sebastian Külps beschränkter Haftung +10719 Berlin 10719 Berlin Julia Maschkow Sitz: Berlin +kundenservice@vanguard.com 030 31196465 Vorsitzender des Aufsichtsrats: Amtsgericht:Charlottenburg, +www.de.vanguard Sean Hagerty Berlin +HRB Nr. 222205 +Umsatzsteuer-ID-Nr. +DE336773878 +Kundenname: Herr Max Matthias Mustermann Seite 2 von 3 +Kundennummer: 12345678 +Bitte beachten Sie Ihre eventuelle Meldepflicht nach § 67 AWV. +Bitte beachten Sie, dass dieser Beleg keine Steuerbescheinigung darstellt. +Dieses Dokument ist maschinell erstellt und wird nicht unterschrieben. +Vanguard Group Europe GmbH Postanschrift: Geschäftsführung: Rechtsform: Gesellschaft mit +Kurfürstendamm 21 Kurfürstendamm 21 Sebastian Külps beschränkter Haftung +10719 Berlin 10719 Berlin Julia Maschkow Sitz: Berlin +kundenservice@vanguard.com 030 31196465 Vorsitzender des Aufsichtsrats: Amtsgericht:Charlottenburg, +www.de.vanguard Sean Hagerty Berlin +HRB Nr. 222205 +Umsatzsteuer-ID-Nr. +DE336773878 +Kundenname: Herr Max Matthias Mustermann Seite 3 von 3 +Kundennummer: 12345678 +Steuerliche Informationen - Bardividende +Bardividende +Portfolio 12345678.001 +Ausschüttungsbetrag EUR 0,64 +Steuerpfl. Betrag nach Freistellungsauftrag EUR 0,45 +Anrechenbare ausländische Quellensteuer EUR 0,00 +Anrechenbare fiktive Quellensteuer EUR +Bemessungsgrundlage für Kapitalertragsteuer EUR 0,45 +Kapitalertragsteuer EUR -0,11 +Solidaritätszuschlag EUR 0,00 +Kirchensteuer EUR 0,00 +Keine Steuerbescheinigung. +Vanguard Group Europe GmbH Postanschrift: Geschäftsführung: Rechtsform: Gesellschaft mit +Kurfürstendamm 21 Kurfürstendamm 21 Sebastian Külps beschränkter Haftung +10719 Berlin 10719 Berlin Julia Maschkow Sitz: Berlin +kundenservice@vanguard.com 030 31196465 Vorsitzender des Aufsichtsrats: Amtsgericht:Charlottenburg, +www.de.vanguard Sean Hagerty Berlin +HRB Nr. 222205 +Umsatzsteuer-ID-Nr. +DE336773878 \ No newline at end of file diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/vanguardgroupeurope/VanguardGroupEuropePDFExtractorTest.java b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/vanguardgroupeurope/VanguardGroupEuropePDFExtractorTest.java index b28a892497..7b7ba4ec64 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/vanguardgroupeurope/VanguardGroupEuropePDFExtractorTest.java +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/vanguardgroupeurope/VanguardGroupEuropePDFExtractorTest.java @@ -1,19 +1,12 @@ package name.abuchen.portfolio.datatransfer.pdf.vanguardgroupeurope; -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.assertNull; - +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.check; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.dividend; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasAmount; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasCurrencyCode; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasDate; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasFees; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasForexGrossValue; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasGrossValue; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasIsin; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasName; @@ -24,6 +17,14 @@ import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasTicker; import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasWkn; 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.assertNull; import java.time.LocalDateTime; import java.util.ArrayList; @@ -34,9 +35,12 @@ import name.abuchen.portfolio.datatransfer.Extractor.BuySellEntryItem; import name.abuchen.portfolio.datatransfer.Extractor.Item; import name.abuchen.portfolio.datatransfer.Extractor.SecurityItem; +import name.abuchen.portfolio.datatransfer.ImportAction.Status; import name.abuchen.portfolio.datatransfer.actions.AssertImportActions; +import name.abuchen.portfolio.datatransfer.actions.CheckCurrenciesAction; import name.abuchen.portfolio.datatransfer.pdf.PDFInputFile; import name.abuchen.portfolio.datatransfer.pdf.VanguardGroupEuropePDFExtractor; +import name.abuchen.portfolio.model.Account; import name.abuchen.portfolio.model.AccountTransaction; import name.abuchen.portfolio.model.BuySellEntry; import name.abuchen.portfolio.model.Client; @@ -213,8 +217,79 @@ public void testDividende01() // check dividende transaction assertThat(results, hasItem(dividend( // hasDate("2023-06-28T00:00"), hasShares(102.185154), // - hasSource("Dividende01.txt"), hasNote("Ordentliche Dividende"), // + hasSource("Dividende01.txt"), // + hasNote("Ordentliche Dividende"), // hasAmount("EUR", 26.91), hasGrossValue("EUR", 33.00), // hasTaxes("EUR", 5.78 + 0.31), hasFees("EUR", 0.00)))); } + + @Test + public void testDividende02() + { + VanguardGroupEuropePDFExtractor extractor = new VanguardGroupEuropePDFExtractor(new Client()); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Dividende02.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.EUR); + + // check security + assertThat(results, hasItem(security( // + hasIsin("IE00B3XXRP09"), hasWkn(null), hasTicker(null), // + hasName("FDIX Vanguard S&P 500 UCITS ETF (USD) Distributing"), // + hasCurrencyCode("USD")))); + + // check dividende transaction + assertThat(results, hasItem(dividend( // + hasDate("2023-09-27T00:00"), hasShares(2.535612), // + hasSource("Dividende02.txt"), // + hasNote("Ordentliche Dividende"), // + hasAmount("EUR", 0.53), hasGrossValue("EUR", 0.64), // + hasForexGrossValue("USD", 0.68), // + hasTaxes("EUR", 0.11), hasFees("EUR", 0.00)))); + } + + @Test + public void testDividende02WithSecurityInEUR() + { + Security security = new Security("FDIX Vanguard S&P 500 UCITS ETF (USD) Distributin", CurrencyUnit.EUR); + security.setIsin("IE00B3XXRP09"); + + Client client = new Client(); + client.addSecurity(security); + + VanguardGroupEuropePDFExtractor extractor = new VanguardGroupEuropePDFExtractor(client); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Dividende02.txt"), errors); + + assertThat(errors, empty()); + assertThat(countSecurities(results), is(0L)); + assertThat(countBuySell(results), is(0L)); + assertThat(countAccountTransactions(results), is(1L)); + assertThat(results.size(), is(1)); + new AssertImportActions().check(results, CurrencyUnit.EUR); + + // check dividends transaction + assertThat(results, hasItem(dividend( // + hasDate("2023-09-27T00:00"), hasShares(2.535612), // + hasSource("Dividende02.txt"), // + hasNote("Ordentliche Dividende"), // + hasAmount("EUR", 0.53), hasGrossValue("EUR", 0.64), // + hasTaxes("EUR", 0.11), hasFees("EUR", 0.00), // + check(tx -> { + CheckCurrenciesAction c = new CheckCurrenciesAction(); + Account account = new Account(); + account.setCurrencyCode(CurrencyUnit.EUR); + Status s = c.process((AccountTransaction) tx, account); + assertThat(s, is(Status.OK_STATUS)); + })))); + } } diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/VanguardGroupEuropePDFExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/VanguardGroupEuropePDFExtractor.java index 21f17b838c..2f72a1352d 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/VanguardGroupEuropePDFExtractor.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/VanguardGroupEuropePDFExtractor.java @@ -1,7 +1,9 @@ package name.abuchen.portfolio.datatransfer.pdf; +import static name.abuchen.portfolio.datatransfer.ExtractorUtils.checkAndSetGrossUnit; import static name.abuchen.portfolio.util.TextUtil.trim; +import name.abuchen.portfolio.datatransfer.ExtrExchangeRate; import name.abuchen.portfolio.datatransfer.pdf.PDFParser.Block; import name.abuchen.portfolio.datatransfer.pdf.PDFParser.DocumentType; import name.abuchen.portfolio.datatransfer.pdf.PDFParser.Transaction; @@ -9,6 +11,7 @@ import name.abuchen.portfolio.model.BuySellEntry; import name.abuchen.portfolio.model.Client; import name.abuchen.portfolio.model.PortfolioTransaction; +import name.abuchen.portfolio.money.Money; @SuppressWarnings("nls") public class VanguardGroupEuropePDFExtractor extends AbstractPDFExtractor @@ -35,73 +38,85 @@ private void addBuySellTransaction() this.addDocumentTyp(type); Transaction pdfTransaction = new Transaction<>(); - pdfTransaction.subject(() -> { - BuySellEntry entry = new BuySellEntry(); - entry.setType(PortfolioTransaction.Type.BUY); - return entry; - }); Block firstRelevantLine = new Block("^Wertpapierabrechnung: Kauf$"); type.addBlock(firstRelevantLine); firstRelevantLine.set(pdfTransaction); - pdfTransaction - // Wertpapierbezeichnung FDBL Vanguard LifeStrategy 60% Equity UCITS ETF - // (EUR) Distributing - // ISIN IE00BMVB5Q68 - // Kurs (Stückpreis) EUR 25,0900 - .section("name", "name1", "isin", "currency") - .match("^Wertpapierbezeichnung (?.*)") - .match("^(?.*)$") - .match("^ISIN (?[A-Z]{2}[A-Z0-9]{9}[0-9])$") - .match("^Kurs \\(.*\\) (?[\\w]{3}) [\\.,\\d]+$") - .assign((t, v) -> { - if (!v.get("name1").startsWith("ISIN")) - v.put("name", v.get("name") + " " + v.get("name1")); - - t.setSecurity(getOrCreateSecurity(v)); - }) - - // Nominal / Stück 11,956954 - .section("shares") - .match("^Nominal \\/ St.ck (?[\\.,\\d]+)$") - .assign((t, v) -> t.setShares(asShares(v.get("shares")))) - - // Ausführungstag / -zeit 03.02.2023 um 11:11:17 Uhr - .section("date", "time") - .match("^Ausf.hrungstag \\/ \\-zeit (?[\\d]{2}\\.[\\d]{2}\\.[\\d]{4}) .* (?