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 Unicredit PDF-Importer to support new transaction #3929

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,38 @@
PDFBox Version: 1.8.16
-----------------------------------------
UniCredit Bank AG
Wertpapiermitteilung
Depotnummer Bankleitzahl Datum
1234 12345678 123 456 00 17.05.2021
Depotinhaber
Max Mustermann
Kontohinweis
Herrn
Max Mustermann Depot
Muster Str. 1
01234 Musterhausen
Filiale
Filiale Musterhausen
Ansprechpartner Telefon
HR. Muster 1234 56789-10
Wertpapiermitteilung - Ertragszahlung für Depotnummer 1234 0123456789
ACATIS GANÉ VALUE EVENT FONDS Wertpapierkennnummer A1T73W / DE000A1T73W9
INHABER-ANTEILE C
Geschäftsjahr 2020/2021
-------------------------------------------------------------------------------------
Stück 0,066
zahlbar mit EUR 15,00 Bruttobetrag EUR 0,99
-------------------------------------------
Valuta 18.05.2021 Gutschrift EUR 0,99
auf Konto 1234 0123456789 Die Kaufabrechnung zur Wiederanlage erhalten Sie separat.
-------------------------------------------------------------------------------------
Erläuterung zur Abrechnung
Referenz 20210517KUP0123456789
Bitte beachten Sie den Rechenschaftsbericht der Investmentgesellschaft.
Diese Abrechnung erfolgt ohne Berücksichtigung der Kapitalertragsteuer sowie
Solidaritätszuschlag und gegebenenfalls Kirchensteuer. Eine eventuell anfallende
Kapitalertragsteuer oder Kapitalertragsteuer-Gutschrift wird separat auf Ihrem
Kontoauszug ausgewiesen.
Bitte Rückseite beachten
BV1234/VK1234/11.2011
Eingestellt am: 20210518 03:29:390 -F1 03 302 G2L3I4UP 123456789 00000012345678 000000001234
@@ -0,0 +1,38 @@
PDFBox Version: 1.8.17
Portfolio Performance Version: 0.68.3
-----------------------------------------
W e r t p a p i e r - A b r e c h n u n g K a u f
- Geschäftsbestätigung vor steuerlicher Behandlung - Kommission außerbörslich
Depotnummer Abrechnungstag Blatt
93714366 02.04.2024 1
Depotart Filiale
Mitarbeiterbetreuung
Kontonummer +49 92 98229271
0000 454 9395742275 EUR Frau bbhcgl
Herrn R e c h n u n g s n u m m e r
cIHMVtxjw ElrBkcblz Ordernummer Abrechnungsnr. Urspr. Abrechnungsnr.
OMSVCGCGmmyNF Str. 6 9-WPK- 9105942 3866639
68270 TZJNiSG Depotinhaber
eTSNPprNx WIpgmIIMq
Nennbetrag Wertpapierbezeichnung Wertpapierkennnummer/ISIN
ST 1,51 DWS ESG EURO MONEY MARKET FUND A0F426 INHABER-ANTEILE O.N. LU0225880524
Zum Kurs von Ausführungstag/Zeit Ausführungsort Verwahrart
EUR 99,31 02.04.2024 18.55.47 Girosammelverwahrung
Abrechnung
Kurswert EUR 149,96
-----------------------
Belastung (vor Steuern) EUR 149,96
Valuta 04.04.2024 -----------------------
Umsatzreferenz: 20240402WAB1515775338
Diese Abrechnung erfolgt ohne Berücksichtigung der Kapitalertragsteuer.
Eine eventuell anfallende Kapitalertragsteuer oder Kapitalertragsteuer-Gutschrift
wird separat auf Ihrem Kontoauszug ausgewiesen.
Kontrahent ist die UniCredit Bank GmbH oder ein Konzernunternehmen.
Die Höhe des von der Kapitalanlagegesellschaft festgelegten Ausgabeaufschlages/
Rücknahmeabschlages können Sie dem Verkaufsprospekt entnehmen.
Die Leistung ist umsatzsteuerbefreit nach § 4 Nr. 8 UStG.
Unsere Umsatzsteuer-Identifikationsnummer: DE 129 273 380.
Bitte Rückseite beachten.
Bitte bewahren Sie diese Geschäftsbestätigung sowie einen eventuell gesondert erstellten Steuer-Informationsbeleg auf.
BV0081/VK0081/12.2023
Eingestellt am: 20240403 07:20:365 -F1 03 300 G1O43A76 366984771 26542710977141 800873677972
@@ -1,5 +1,28 @@
package name.abuchen.portfolio.datatransfer.pdf.unicredit;

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;
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.purchase;
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;
Expand All @@ -15,12 +38,15 @@
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.PDFInputFile;
import name.abuchen.portfolio.datatransfer.pdf.UnicreditPDFExtractor;
import name.abuchen.portfolio.model.AccountTransaction;
import name.abuchen.portfolio.model.BuySellEntry;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.Portfolio;
import name.abuchen.portfolio.model.PortfolioTransaction;
import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.model.Transaction.Unit;
Expand Down Expand Up @@ -63,7 +89,7 @@ public void testWertpapierKauf01()
assertThat(entry.getPortfolioTransaction().getDateTime(), is(LocalDateTime.parse("2016-02-15T16:28:03")));
assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(22)));
assertThat(entry.getSource(), is("Kauf01.txt"));
assertThat(entry.getNote(), is("Umsatzreferenz: 20160215WAB1861426155"));
assertThat(entry.getNote(), is("Ref.-Nr.: 20160215WAB1861426155"));

assertThat(entry.getPortfolioTransaction().getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1560.83))));
Expand Down Expand Up @@ -107,7 +133,7 @@ public void testWertpapierKauf02()
assertThat(entry.getPortfolioTransaction().getDateTime(), is(LocalDateTime.parse("2021-04-20T03:53:15")));
assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(25)));
assertThat(entry.getSource(), is("Kauf02.txt"));
assertThat(entry.getNote(), is("Umsatzreferenz: 20210421WAB1799275492"));
assertThat(entry.getNote(), is("Ref.-Nr.: 20210421WAB1799275492"));

assertThat(entry.getPortfolioTransaction().getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(4963.46))));
Expand All @@ -129,38 +155,94 @@ public void testWertpapierKauf03()
List<Item> results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Kauf03.txt"), errors);

assertThat(errors, empty());
assertThat(countSecurities(results), is(1L));
assertThat(countBuySell(results), is(1L));
assertThat(countAccountTransactions(results), is(0L));
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("US0605051046"));
assertThat(security.getWkn(), is("858388"));
assertNull(security.getTickerSymbol());
assertThat(security.getName(), is("BANK OF AMERICA CORP. REGISTERED SHARES DL 0,01"));
assertThat(security.getCurrencyCode(), is(CurrencyUnit.EUR));
assertThat(results, hasItem(security( //
hasIsin("US0605051046"), hasWkn("858388"), hasTicker(null), //
hasName("BANK OF AMERICA CORP. REGISTERED SHARES DL 0,01"), //
hasCurrencyCode("USD"))));

// check buy sell transaction
BuySellEntry entry = (BuySellEntry) results.stream().filter(BuySellEntryItem.class::isInstance).findFirst()
.orElseThrow(IllegalArgumentException::new).getSubject();
assertThat(results, hasItem(purchase( //
hasDate("2022-04-01T15:30"), hasShares(460), //
hasSource("Kauf03.txt"), //
hasNote("Ref.-Nr.: 20220404WAB1406946452"), //
hasAmount("EUR", 17454.91), hasGrossValue("EUR", 17454.91), //
hasForexGrossValue("USD", 19200.40), //
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00))));
}

assertThat(entry.getPortfolioTransaction().getType(), is(PortfolioTransaction.Type.BUY));
assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.BUY));
@Test
public void testWertpapierKauf03WithSecurityInEUR()
{
Security security = new Security("BANK OF AMERICA CORP. REGISTERED SHARES DL 0,01", CurrencyUnit.EUR);
security.setIsin("US0605051046");
security.setWkn("858388");

assertThat(entry.getPortfolioTransaction().getDateTime(), is(LocalDateTime.parse("2022-04-01T15:30")));
assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(460)));
assertThat(entry.getSource(), is("Kauf03.txt"));
assertThat(entry.getNote(), is("Umsatzreferenz: 20220404WAB1406946452"));
Client client = new Client();
client.addSecurity(security);

assertThat(entry.getPortfolioTransaction().getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(17454.91))));
assertThat(entry.getPortfolioTransaction().getGrossValue(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(17454.91))));
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))));
UnicreditPDFExtractor extractor = new UnicreditPDFExtractor(client);

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

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

assertThat(errors, empty());
assertThat(countSecurities(results), is(0L));
assertThat(countBuySell(results), is(1L));
assertThat(countAccountTransactions(results), is(0L));
assertThat(results.size(), is(1));
new AssertImportActions().check(results, CurrencyUnit.EUR);

// check buy sell transaction
assertThat(results, hasItem(purchase( //
hasDate("2022-04-01T15:30"), hasShares(460), //
hasSource("Kauf03.txt"), //
hasNote("Ref.-Nr.: 20220404WAB1406946452"), //
hasAmount("EUR", 17454.91), hasGrossValue("EUR", 17454.91), //
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00), //
check(tx -> {
CheckCurrenciesAction c = new CheckCurrenciesAction();
Status s = c.process((PortfolioTransaction) tx, new Portfolio());
assertThat(s, is(Status.OK_STATUS));
}))));
}

@Test
public void testWertpapierKauf04()
{
UnicreditPDFExtractor extractor = new UnicreditPDFExtractor(new Client());

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

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

assertThat(errors, empty());
assertThat(countSecurities(results), is(1L));
assertThat(countBuySell(results), is(1L));
assertThat(countAccountTransactions(results), is(0L));
assertThat(results.size(), is(2));
new AssertImportActions().check(results, CurrencyUnit.EUR);

// check security
assertThat(results, hasItem(security( //
hasIsin("LU0225880524"), hasWkn("A0F426"), hasTicker(null), //
hasName("DWS ESG EURO MONEY MARKET FUND INHABER-ANTEILE O.N."), //
hasCurrencyCode("EUR"))));

// check buy sell transaction
assertThat(results, hasItem(purchase( //
hasDate("2024-04-02T18:55:47"), hasShares(1.51), //
hasSource("Kauf04.txt"), //
hasNote("Ref.-Nr.: 20240402WAB1515775338"), //
hasAmount("EUR", 149.96), hasGrossValue("EUR", 149.96), //
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00))));
}

@Test
Expand Down Expand Up @@ -195,7 +277,7 @@ public void testWertpapierVerkauf01()
assertThat(entry.getPortfolioTransaction().getDateTime(), is(LocalDateTime.parse("2021-04-16T12:38:47")));
assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(90)));
assertThat(entry.getSource(), is("Verkauf01.txt"));
assertThat(entry.getNote(), is("Umsatzreferenz: 20210416WAB1798426394"));
assertThat(entry.getNote(), is("Ref.-Nr.: 20210416WAB1798426394"));

assertThat(entry.getPortfolioTransaction().getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(8175.91))));
Expand All @@ -207,12 +289,43 @@ public void testWertpapierVerkauf01()
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(41.09))));
}

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

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

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

assertThat(errors, empty());
assertThat(countSecurities(results), is(1L));
assertThat(countBuySell(results), is(1L));
assertThat(countAccountTransactions(results), is(0L));
assertThat(results.size(), is(2));
new AssertImportActions().check(results, CurrencyUnit.EUR);

// check security
assertThat(results, hasItem(security( //
hasIsin("IE00BK5BQV03"), hasWkn("A2PLS9"), hasTicker(null), //
hasName("VANG.FTSE DEVELOP.WORLD U.ETF REGISTERED SHARES USD ACC.ON"), //
hasCurrencyCode("EUR"))));

// check buy sell transaction
assertThat(results, hasItem(sale( //
hasDate("2024-01-09T10:33:28"), hasShares(50.00), //
hasSource("Verkauf02.txt"), //
hasNote("Ref.-Nr.: 20240109WAB1302517526"), //
hasAmount("EUR", 4208.44), hasGrossValue("EUR", 4222.50), //
hasTaxes("EUR", 0.00), hasFees("EUR", 14.06))));
}

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

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

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

Expand All @@ -238,7 +351,7 @@ public void testDividende01()
assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2021-05-18T00:00")));
assertThat(transaction.getShares(), is(Values.Share.factorize(0.066)));
assertThat(transaction.getSource(), is("Dividende01.txt"));
assertNull(transaction.getNote());
assertThat(transaction.getNote(), is("Ref.-Nr.: 20210517KUP0123456789"));

assertThat(transaction.getMonetaryAmount(),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.99))));
Expand All @@ -249,4 +362,35 @@ public void testDividende01()
assertThat(transaction.getUnitSum(Unit.Type.FEE),
is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(0.00))));
}

@Test
public void testDividende02()
{
UnicreditPDFExtractor extractor = new UnicreditPDFExtractor(new Client());

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

List<Item> 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("DE000A1T73W9"), hasWkn("A1T73W"), hasTicker(null), //
hasName("ACATIS GANÉ VALUE EVENT FONDS INHABER-ANTEILE C"), //
hasCurrencyCode("EUR"))));

// check dividends transaction
assertThat(results, hasItem(dividend( //
hasDate("2021-05-18T00:00"), hasShares(0.066), //
hasSource("Dividende02.txt"), //
hasNote("Ref.-Nr.: 20210517KUP0123456789"), //
hasAmount("EUR", 0.99), hasGrossValue("EUR", 0.99), //
hasTaxes("EUR", 0.00), hasFees("EUR", 0.00))));
}
}