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 MLP Banking AG PDF-Importer to support new transactions #2742

Merged
merged 2 commits into from Mar 26, 2022
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,60 @@
PDFBox Version: 1.8.16
-----------------------------------------
MLP Banking AG · Alte Heerstraße 40 · 69168 Wiesloch Seite 1 von 2
Depotnummer 8505679654
Kundennummer 9999999
Max Mustermann
Auftragsnummer 638328/75.00
Max Mustermann Datum 03.03.2022
Musterstraße 10 Rechnungsnummer W00866-00001111111/22
11111 Musterstadt Umsatzsteuer-ID DE111111111
Vermögensdepot
0016
Wertpapier Abrechnung Verkauf
Auftrag vom 01.03.2022 10:36:00 Uhr
Nominale Wertpapierbezeichnung ISIN (WKN)
Stück 8,104 DWS CON.DJE ALPHA RENT.GLOBAL LU0087412390 (974515)
INHABER-ANTEILE LC O.N.
Handels-/Ausführungsplatz Außerbörslich
Schlusstag 01.03.2022
Ausführungskurs 135,74 EUR
Girosammelverw. mehrere Sammelurkunden - kein Stückeausdruck -
Kurswert 1.100,04 EUR
Ermittlung steuerrelevante Erträge
Veräußerungsverlust 3,00- EUR
Eingebuchte sonstige negative Kapitalerträge 3,00 EUR
Ausmachender Betrag 1.100,04 EUR
Den Gegenwert buchen wir mit Valuta 03.03.2022 zu Gunsten des Kontos 505679278
(IBAN DE11 1111 0000 0111 1111 11), BLZ 67230000 (BIC MLPBDE61XXX).
Die Wertpapiere entnehmen wir Ihrem Depotkonto.
Steuerliche Ausgleichrechnung
Verrechnete sonstige negative Kapitalerträge 3,00- EUR
Berechnungsgrundlage für die Kapitalertragsteuer 3,00 EUR
0866.03032049.0016501OR07
Seite 2 von 2
Depotnummer 11111111
Kundennummer 9999999
Auftragsnummer 638328/75.00
Datum 03.03.2022
Kapitalertragsteuer 25,00% auf 3,00 EUR 0,75 EUR
Solidaritätszuschlag 5,50% auf 0,75 EUR 0,04 EUR
Ausmachender Betrag 0,79 EUR
Den Gegenwert buchen wir mit Valuta 03.03.2022 zu Gunsten des Kontos 1111111111111
(IBAN DE11 1111 0000 0111 1111 11), BLZ 67230000 (BIC MLPBDE61XXX).
Sofern keine Umsatzsteuer ausgewiesen ist, handelt es sich um eine umsatzsteuerbefreite Finanzdienstleistung.
Nachrichtlich die Übersicht Ihrer Verrechnungs- und Steuertopfsalden zum Zeitpunkt der Erstellung der Abrechnung.
Verlustverrechnungstöpfe 2022 Berechnungsgrundlage
der gezahlten Steuern
Euro Aktien Sonstige Sparer- anrechenbare Aktien und Sonstige
Pauschbetrag Quellensteuer
Vorher 0,00 0,00 0,00 0,00 31.980,37
Verkauf 0,00 3,00 0,00 0,00 0,00
Steuerausgleich 0,00 3,00- 0,00 0,00 3,00-
Nachher 0,00 0,00 0,00 0,00 31.977,37
Berücksichtigte Anschaffungsgeschäfte (alle ermittelten Beträge in EUR)
Geschäft Auftragsnr. Ausführ.-tag Whr./St. Nennwert/Stück AS-Kosten Erlös Teilfrei- ant. Ergebnis
stellung
Kauf 4884246100 18.02.2022 Stück 8,1040 1.103,04- 1.100,04 0,00 3,00- (D)
Summe aller Erträge nach Differenzmethode und/oder Ersatzbemessungsgrundlage 3,00-
Dieses Dokument wurde maschinell erstellt und wird nicht unterschrieben.
0866.03032049.0016502OR07
@@ -0,0 +1,65 @@
PDFBox Version: 1.8.16
-----------------------------------------
MLP Banking AG · Alte Heerstraße 40 · 69168 Wiesloch Seite 1 von 2
Depotnummer 8505679654
Kundennummer 9999999
Max Mustermann
Auftragsnummer 638328/43.00
Max Mustermann Datum 21.02.2022
Musterstraße 10 Rechnungsnummer W00866-00001111111/22
11111 Musterstadt Umsatzsteuer-ID DE111111111
Vermögensdepot
0016
Wertpapier Abrechnung Verkauf
Auftrag vom 16.02.2022 10:07:58 Uhr
Nominale Wertpapierbezeichnung ISIN (WKN)
Stück 163,269 AB SICAV I-AMERICAN GROWTH PTF LU0079474960 (986838)
ACTIONS NOM. A O.N.
Handels-/Ausführungsplatz Außerbörslich
Schlusstag 16.02.2022
Ausführungskurs 167,82 USD
Wertpapierrechnung Lagerland Luxemburg
Devisenkurs (EUR/USD) 1,141 vom 18.02.2022
Kurswert 24.013,85 EUR
Ermittlung steuerrelevante Erträge
Veräußerungsgewinn (nach Teilfreistellung) 2.809,62 EUR
Berechnungsgrundlage für die Kapitalertragsteuer 2.809,62 EUR
Steuerberechnung
Kapitalertragsteuer 25,00% auf 2.809,62 EUR 702,41- EUR
Solidaritätszuschlag 5,50% auf 702,41 EUR 38,63- EUR
Ausmachender Betrag 23.272,81 EUR
Den Gegenwert buchen wir mit Valuta 22.02.2022 zu Gunsten des Kontos 1111111111111
(IBAN DE11 1111 0000 0111 1111 11), BLZ 67230000 (BIC MLPBDE61XXX).
Die Wertpapiere entnehmen wir Ihrem Depotkonto.
Sofern keine Umsatzsteuer ausgewiesen ist, handelt es sich um eine umsatzsteuerbefreite Finanzdienstleistung.
0866.02220819.0002871OR07
Seite 2 von 2
Depotnummer 8505679654
Kundennummer 9999999
Auftragsnummer 638328/43.00
Datum 21.02.2022
Nachrichtlich die Übersicht Ihrer Verrechnungs- und Steuertopfsalden zum Zeitpunkt der Erstellung der Abrechnung.
Verlustverrechnungstöpfe 2022 Berechnungsgrundlage
der gezahlten Steuern
Euro Aktien Sonstige Sparer- anrechenbare Aktien und Sonstige
Pauschbetrag Quellensteuer
Vorher 0,00 0,00 0,00 0,00 25.554,21
Verkauf 0,00 0,00 0,00 0,00 2.809,62
Nachher 0,00 0,00 0,00 0,00 28.363,83
Berücksichtigte Anschaffungsgeschäfte (alle ermittelten Beträge in EUR)
Geschäft Auftragsnr. Ausführ.-tag Whr./St. Nennwert/Stück AS-Kosten Erlös Teilfrei- ant. Ergebnis
stellung
Kauf 5676107400 17.11.2020 Stück 33,1020 3.999,94- 4.868,41 260,54- 607,93 (D)
Fondskorrekturfaktoren *) zur Anschaffung: VAP: 0,42
Kauf 5857561400 01.12.2020 Stück 32,9340 3.999,91- 4.843,84 253,18- 590,75 (D)
Fondskorrekturfaktoren *) zur Anschaffung: VAP: 0,42
Kauf 6251034600 04.01.2021 Stück 33,0870 3.999,92- 4.866,49 259,97- 606,60 (D)
Fondskorrekturfaktoren *) zur Anschaffung: VAP: 0,42
Kauf 6670656600 01.02.2021 Stück 32,2260 4.000,00- 4.739,85 221,95- 517,90 (D)
Fondskorrekturfaktoren *) zur Anschaffung: VAP: 0,42
Kauf 7099905600 01.03.2021 Stück 31,9200 3.999,92- 4.694,84 208,48- 486,44 (D)
Fondskorrekturfaktoren *) zur Anschaffung: VAP: 0,42
Summe aller Erträge nach Differenzmethode und/oder Ersatzbemessungsgrundlage 2.809,62
*VAP: Vorabpauschale (verringert den anteiligen Veräußerungserlös)
Dieses Dokument wurde maschinell erstellt und wird nicht unterschrieben.
0866.02220819.0002872OR07
@@ -1,35 +1,39 @@
package name.abuchen.portfolio.datatransfer.pdf.mlpbank;

import static org.hamcrest.CoreMatchers.instanceOf;
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;
import java.util.List;
import java.util.Optional;

import org.junit.Test;

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.Extractor.TransactionItem;
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.MLPBankingAGPDFExtractor;
import name.abuchen.portfolio.datatransfer.pdf.PDFInputFile;
import name.abuchen.portfolio.model.Account;
import name.abuchen.portfolio.model.AccountTransaction;
import name.abuchen.portfolio.model.BuySellEntry;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.PortfolioTransaction;
import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.model.Transaction.Unit;
import name.abuchen.portfolio.money.CurrencyUnit;
import name.abuchen.portfolio.money.Money;
import name.abuchen.portfolio.money.Values;

@SuppressWarnings("nls")
public class mlpbankPDFExtractorTest
{

@Test
public void testWertpapierKauf01()
{
Expand All @@ -41,26 +45,189 @@ public void testWertpapierKauf01()

assertThat(errors, empty());
assertThat(results.size(), is(2));
new AssertImportActions().check(results, CurrencyUnit.EUR);

// check security
Security security = results.stream().filter(i -> i instanceof SecurityItem).findFirst()
Security security = results.stream().filter(SecurityItem.class::isInstance).findFirst()
.orElseThrow(IllegalArgumentException::new).getSecurity();
assertThat(security.getIsin(), is("LU0106280836"));
assertThat(security.getWkn(), is("930920"));
assertThat(security.getName(), is("SAUREN GLOBAL BALANCED INHABER-ANTEILE A O.N"));
assertThat(security.getCurrencyCode(), is(CurrencyUnit.EUR));

// check buy sell transaction
Optional<Item> item = results.stream().filter(i -> i instanceof BuySellEntryItem).findFirst();
assertThat(item.orElseThrow(IllegalArgumentException::new).getSubject(), instanceOf(BuySellEntry.class));
BuySellEntry entry = (BuySellEntry) item.orElseThrow(IllegalArgumentException::new).getSubject();
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().getAmount(), is(Values.Amount.factorize(100.01)));
assertThat(entry.getPortfolioTransaction().getDateTime(), is(LocalDateTime.parse("2021-01-14T00:00")));
assertThat(entry.getPortfolioTransaction().getDateTime(),is(LocalDateTime.parse("2021-01-14T00:00")));
assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(4.929)));
assertThat(entry.getSource(), is("Kauf01.txt"));
assertNull(entry.getNote());

assertThat(entry.getPortfolioTransaction().getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(100.01))));
assertThat(entry.getPortfolioTransaction().getGrossValue(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(100.01))));
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(0.00))));
}

@Test
public void testWertpapierVerkauf01()
{
MLPBankingAGPDFExtractor extractor = new MLPBankingAGPDFExtractor(new Client());

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

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

assertThat(errors, empty());
assertThat(results.size(), is(3));
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("LU0087412390"));
assertThat(security.getWkn(), is("974515"));
assertThat(security.getName(), is("DWS CON.DJE ALPHA RENT.GLOBAL INHABER-ANTEILE LC 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.SELL));
assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.SELL));

assertThat(entry.getPortfolioTransaction().getDateTime(),is(LocalDateTime.parse("2022-03-01T00:00")));
assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(8.104)));
assertThat(entry.getSource(), is("Verkauf01.txt"));
assertThat(entry.getNote(), is("Veräußerungsverlust 3,00- EUR"));

assertThat(entry.getPortfolioTransaction().getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1100.04))));
assertThat(entry.getPortfolioTransaction().getGrossValue(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1100.04))));
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(0.00))));

// check tax refund transaction
AccountTransaction transaction = (AccountTransaction) results.stream().filter(TransactionItem.class::isInstance)
.findFirst().orElseThrow(IllegalArgumentException::new).getSubject();

assertThat(transaction.getType(), is(AccountTransaction.Type.TAX_REFUND));

assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2022-03-03T00:00")));
assertThat(transaction.getShares(), is(Values.Share.factorize(8.104)));
assertThat(transaction.getSource(), is("Verkauf01.txt"));
assertNull(transaction.getNote());

assertThat(transaction.getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.79))));
assertThat(transaction.getGrossValue(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.79))));
assertThat(transaction.getUnitSum(Unit.Type.TAX),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.00))));
assertThat(transaction.getUnitSum(Unit.Type.FEE),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.00))));
}

@Test
public void testWertpapierVerkauf02()
{
MLPBankingAGPDFExtractor extractor = new MLPBankingAGPDFExtractor(new Client());

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

List<Item> results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Verkauf02.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("LU0079474960"));
assertThat(security.getWkn(), is("986838"));
assertThat(security.getName(), is("AB SICAV I-AMERICAN GROWTH PTF ACTIONS NOM. A O.N."));
assertThat(security.getCurrencyCode(), is(CurrencyUnit.USD));

// 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.SELL));
assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.SELL));

assertThat(entry.getPortfolioTransaction().getDateTime(),is(LocalDateTime.parse("2022-02-16T00:00")));
assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(163.269)));
assertThat(entry.getSource(), is("Verkauf02.txt"));
assertNull(entry.getNote());

assertThat(entry.getPortfolioTransaction().getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(23272.81))));
assertThat(entry.getPortfolioTransaction().getGrossValue(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(24013.85))));
assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.TAX),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(702.41 + 38.63))));
assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.FEE),
is(Money.of("EUR", Values.Amount.factorize(0.00))));
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.00))));
}

@Test
public void testWertpapierVerkauf02WithSecurityInEUR()
{
Security security = new Security("AB SICAV I-AMERICAN GROWTH PTF ACTIONS NOM. A O.N.", CurrencyUnit.EUR);
security.setIsin("LU0079474960");
security.setWkn("986838");

Client client = new Client();
client.addSecurity(security);

MLPBankingAGPDFExtractor extractor = new MLPBankingAGPDFExtractor(client);

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

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

assertThat(errors, empty());
assertThat(results.size(), is(1));
new AssertImportActions().check(results, 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.SELL));
assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.SELL));

assertThat(entry.getPortfolioTransaction().getDateTime(),is(LocalDateTime.parse("2022-02-16T00:00")));
assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(163.269)));
assertThat(entry.getSource(), is("Verkauf02.txt"));
assertNull(entry.getNote());

assertThat(entry.getPortfolioTransaction().getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(23272.81))));
assertThat(entry.getPortfolioTransaction().getGrossValue(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(24013.85))));
assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.TAX),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(702.41 + 38.63))));
assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.FEE),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.00))));

CheckCurrenciesAction c = new CheckCurrenciesAction();
Account account = new Account();
account.setCurrencyCode(CurrencyUnit.EUR);
Status s = c.process(entry, account, entry.getPortfolio());
assertThat(s, is(Status.OK_STATUS));
}
}