Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify Vanguard PDF-Importer to support new transactions #3429

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,81 @@
PDFBox Version: 1.8.17
Portfolio Performance Version: 0.64.0
-----------------------------------------
So erreichen Sie uns:
Web: www.de.vanguard
Telefon: (030) 3119 6465
E-Mail: kundenservice@vanguard.com
Herr
Total Egal
Dumdideldumweg 19
12345 Investcity 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 FDBL Vanguard LifeStrategy 60% Equity UCITS
ETF (EUR) Distributing (IE00BMVB5Q68)
ISIN IE00BMVB5Q68
Verwahrart Wertpapierrechnung
Lagerland Luxemburg
Nominal/Stück 102,185154 ST
Währung EUR
Ausschüttung EUR 0,322898 pro Stück
Dividendenart Ordentliche Dividende
Periodizität Siehe Ausschüttungskalender
Zahlungsdatum 28.06.2023
Ex-Tag 15.06.2023
Bruttobetrag EUR 33,00
Kapitalertragsteuer EUR -5,78
Solidaritätszuschlag EUR -0,31
Kirchensteuer EUR 0,00
Netto-Betrag EUR 26,91
Ausmachender Betrag EUR 26,91
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 Total Egal Seite 2 von 3
Kundennummer: 12345678
Der Abrechnungsbetrag wird mit Valuta 28.6.2023 über Ihr Konto 12345678 gebucht.
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 Total Egal Seite 3 von 3
Kundennummer: 12345678
Steuerliche Informationen - Bardividende
Bardividende
Portfolio 12345678.001
Ausschüttungsbetrag EUR 33,00
Steuerpfl. Betrag nach Freistellungsauftrag EUR 23,10
Anrechenbare ausländische Quellensteuer EUR 0,00
Anrechenbare fiktive Quellensteuer EUR
Bemessungsgrundlage für Kapitalertragsteuer EUR 23,10
Kapitalertragsteuer EUR -5,78
Solidaritätszuschlag EUR -0,31
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
@@ -1,10 +1,30 @@
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.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.hasGrossValue;
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasIsin;
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasName;
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasNote;
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasShares;
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasSource;
import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasTaxes;
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 java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -167,4 +187,33 @@ public void testWertpapierKauf03()
assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.FEE),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.00))));
}

@Test
public void testDividende01()
{
VanguardGroupEuropePDFExtractor extractor = new VanguardGroupEuropePDFExtractor(new Client());

List<Exception> errors = new ArrayList<>();

List<Item> results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Dividende01.txt"), errors);

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("IE00BMVB5Q68"), hasWkn(null), hasTicker(null), //
hasName("FDBL Vanguard LifeStrategy 60% Equity UCITS ETF (EUR) Distributing"), //
hasCurrencyCode("EUR"))));

// check dividende transaction
assertThat(results, hasItem(dividend( //
hasDate("2023-06-28T00:00"), hasShares(102.185154), //
hasSource("Dividende01.txt"), hasNote("Ordentliche Dividende"), //
hasAmount("EUR", 26.91), hasGrossValue("EUR", 33.00), //
hasTaxes("EUR", 5.78 + 0.31), hasFees("EUR", 0.00))));
}
}
Expand Up @@ -5,6 +5,7 @@
import name.abuchen.portfolio.datatransfer.pdf.PDFParser.Block;
import name.abuchen.portfolio.datatransfer.pdf.PDFParser.DocumentType;
import name.abuchen.portfolio.datatransfer.pdf.PDFParser.Transaction;
import name.abuchen.portfolio.model.AccountTransaction;
import name.abuchen.portfolio.model.BuySellEntry;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.PortfolioTransaction;
Expand All @@ -19,6 +20,7 @@ public VanguardGroupEuropePDFExtractor(Client client)
addBankIdentifier("Vanguard Group Europe GmbH");

addBuySellTransaction();
addDividendTransaction();
}

@Override
Expand Down Expand Up @@ -101,4 +103,101 @@ private void addBuySellTransaction()

.wrap(BuySellEntryItem::new);
}

private void addDividendTransaction()
{
DocumentType type = new DocumentType("Bardividende");
this.addDocumentTyp(type);

Block block = new Block("^Bardividende$", "^Steuerliche Informationen .*$");
type.addBlock(block);
Transaction<AccountTransaction> pdfTransaction = new Transaction<>();

pdfTransaction.subject(() -> {
AccountTransaction entry = new AccountTransaction();
entry.setType(AccountTransaction.Type.DIVIDENDS);
return entry;
});

pdfTransaction
// @formatter:off
// Wertpapierbezeichnung FDBL Vanguard LifeStrategy 60% Equity UCITS
// ETF (EUR) Distributing (IE00BMVB5Q68)
// ISIN IE00BMVB5Q68
// Währung EUR
// @formatter:on
.section("name", "name1", "isin", "currency")
.match("^Wertpapierbezeichnung (?<name>.*)$")
.match("^(?<name1>.*) \\([A-Z]{2}[A-Z0-9]{9}[0-9]\\)$")
.match("^ISIN (?<isin>[A-Z]{2}[A-Z0-9]{9}[0-9])$")
.match("^W.hrung (?<currency>[\\w]{3})$")
.assign((t, v) -> {
if (!v.get("name1").startsWith("ISIN"))
v.put("name", trim(v.get("name")) + " " + trim(v.get("name1")));

t.setSecurity(getOrCreateSecurity(v));
})

// @formatter:off
// Nominal/Stück 102,185154 ST
// @formatter:on
.section("shares")
.match("^Nominal\\/St.ck (?<shares>[\\.,\\d]+) ST$")
.assign((t, v) -> t.setShares(asShares(v.get("shares"))))

// @formatter:off
// Zahlungsdatum 28.06.2023
// @formatter:on
.section("date")
.match("^Zahlungsdatum (?<date>[\\d]{2}\\.[\\d]{2}\\.[\\d]{4})$")
.assign((t, v) -> t.setDateTime(asDate(v.get("date"))))

// @formatter:off
// Ausmachender Betrag EUR 26,91
// @formatter:on
.section("currency", "amount")
.match("^Ausmachender Betrag (?<currency>[\\w]{3}) (?<amount>[\\.,\\d]+)$")
.assign((t, v) -> {
t.setAmount(asAmount(v.get("amount")));
t.setCurrencyCode(asCurrencyCode(v.get("currency")));
})

// @formatter:off
// Dividendenart Ordentliche Dividende
// @formatter:on
.section("note").optional()
.match("^Dividendenart (?<note>.*)$")
.assign((t, v) -> t.setNote(trim(v.get("note"))))

.wrap(TransactionItem::new);

addTaxesSectionsTransaction(pdfTransaction, type);

block.set(pdfTransaction);
}

private <T extends Transaction<?>> void addTaxesSectionsTransaction(T transaction, DocumentType type)
{
transaction
// @formatter:off
// Kapitalertragsteuer EUR -5,78
// @formatter:on
.section("currency", "tax").optional()
.match("^Kapitalertrag(s)?steuer (?<currency>[\\w]{3}) \\-(?<tax>[\\.,\\d]+)$")
.assign((t, v) -> processTaxEntries(t, v, type))

// @formatter:off
// Solidaritätszuschlag EUR -0,31
// @formatter:on
.section("currency", "tax").optional()
.match("^Solidarit.tszuschlag (?<currency>[\\w]{3}) \\-(?<tax>[\\.,\\d]+)$")
.assign((t, v) -> processTaxEntries(t, v, type))

// @formatter:off
// Kirchensteuer EUR 0,00
// @formatter:on
.section("currency", "tax").optional()
.match("^Kirchensteuer (?<currency>[\\w]{3}) \\-(?<tax>[\\.,\\d]+)$")
.assign((t, v) -> processTaxEntries(t, v, type));
}
}