diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/CryptoVerkauf01.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/CryptoVerkauf01.txt new file mode 100644 index 0000000000..cb306b239d --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/CryptoVerkauf01.txt @@ -0,0 +1,33 @@ +PDFBox Version: 1.8.17 +Portfolio Performance Version: 0.65.3 +----------------------------------------- +TRADE REPUBLIC BANK GMBH KASTANIENALLEE 32 10435 BERLIN +Max Mustermann SEITE 1 von 1 +Musterstraße 1 DATUM 10.01.2022 +01234 Musterstadt ORDER 25a4-7fba +AUSFÜHRUNG dd26-52b9 +CRYPTO-WALLET BitGo +DEPOT 0123456789 +ABRECHNUNG CRYPTOGESCHÄFT +ÜBERSICHT +Market-Order Verkauf am 10.01.2022, um 16:11 Uhr (Europe/Berlin) im außerbörslichen Handel (Bankhaus +Scheich). +Der Kontrahent der Transaktion ist Bankhaus Scheich Wertpapierspezialist AG. +POSITION ANZAHL KURS BETRAG +Ethereum (ETH) 0,1 Stk. 2.628,45 EUR 262,85 EUR +GESAMT 262,85 EUR +ABRECHNUNG +POSITION BETRAG +Fremdkostenzuschlag -1,00 EUR +GESAMT 261,85 EUR +BUCHUNG +VERRECHNUNGSKONTO VALUTA BETRAG +DE99012345670123456789 10.01.2022 261,85 EUR +Diese Abrechnung wird maschinell erstellt und daher nicht unterschrieben. +Die Cryptowerte werden in einer zentralen Wallet bei dem Cryptoverwahrer BitGo Deutschland GmbH verwahrt. +Cryptowährungen unterfallen derzeit nicht der Abgeltungssteuer. Deshalb haben wir noch keine Steuern für +Dich abgeführt. Bitte prüfe aber mit Deinem Steuerberater, inwieweit Du Steuern abführen musst. Trade +Republic erbringt keine Steuerberatung. +Trade Republic Bank GmbH www.traderepublic.com Sitz der Gesellschaft: Düsseldorf Geschäftsführer +Kastanienallee 32 service@traderepublic.com AG Düsseldorf HRB 85864 Andreas Willius +10435 Berlin USt-ID DE307510626 Karsten Müller \ No newline at end of file diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicPDFExtractorTest.java b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicPDFExtractorTest.java index 222fbc9f56..96dd7538da 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicPDFExtractorTest.java +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicPDFExtractorTest.java @@ -1,14 +1,5 @@ package name.abuchen.portfolio.datatransfer.pdf.traderepublic; -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; @@ -28,7 +19,16 @@ 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; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.time.LocalDateTime; @@ -436,6 +436,37 @@ public void testKauf08() is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1.00)))); } + @Test + public void testWertpapierKauf09() + { + TradeRepublicPDFExtractor extractor = new TradeRepublicPDFExtractor(new Client()); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Kauf09.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("DE000SQ6QKU9"), hasWkn(null), hasTicker(null), // + hasName("Société Générale Effekten GmbH MiniL O.End CBOE VIX 11,49"), // + hasCurrencyCode("EUR")))); + + // check buy sell transaction + assertThat(results, hasItem(purchase( // + hasDate("2023-04-28T11:13"), hasShares(100.0), // + hasSource("Kauf09.txt"), // + hasNote(null), // + hasAmount("EUR", 87.40), hasGrossValue("EUR", 86.40), // + hasTaxes("EUR", 0.00), hasFees("EUR", 1.00)))); + } + @Test public void testCryptoKauf01() { @@ -590,13 +621,11 @@ public void testCryptoKauf05() } @Test - public void testWertpapierKauf15() + public void testCryptoVerkauf01() { - TradeRepublicPDFExtractor extractor = new TradeRepublicPDFExtractor(new Client()); - List errors = new ArrayList<>(); - List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Kauf09.txt"), errors); + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "CryptoVerkauf01.txt"), errors); assertThat(errors, empty()); assertThat(countSecurities(results), is(1L)); @@ -607,16 +636,18 @@ public void testWertpapierKauf15() // check security assertThat(results, hasItem(security( // - hasIsin("DE000SQ6QKU9"), hasWkn(null), hasTicker(null), // - hasName("Société Générale Effekten GmbH MiniL O.End CBOE VIX 11,49"), // - hasCurrencyCode("EUR")))); + hasIsin(null), hasWkn(null), hasTicker("ETH"), // + hasName("Ethereum"), // + hasCurrencyCode("EUR"), // + hasFeed(CoinGeckoQuoteFeed.ID), // + hasFeedProperty(CoinGeckoQuoteFeed.COINGECKO_COIN_ID, "ethereum")))); // check buy sell transaction - assertThat(results, hasItem(purchase( // - hasDate("2023-04-28T11:13"), hasShares(100.0), // - hasSource("Kauf09.txt"), // - hasNote(null), // - hasAmount("EUR", 87.40), hasGrossValue("EUR", 86.40), // + assertThat(results, hasItem(sale( // + hasDate("2022-01-10T16:11"), hasShares(0.1), // + hasSource("CryptoVerkauf01.txt"), // + hasNote("Order: 25a4-7fba | Ausführung: dd26-52b9"), // + hasAmount("EUR", 261.85), hasGrossValue("EUR", 262.85), // hasTaxes("EUR", 0.00), hasFees("EUR", 1.00)))); } diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/TradeRepublicPDFExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/TradeRepublicPDFExtractor.java index a82532bf83..bbf8b03e57 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/TradeRepublicPDFExtractor.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/TradeRepublicPDFExtractor.java @@ -50,299 +50,275 @@ public String getLabel() private void addBuySellTransaction() { - DocumentType type = new DocumentType("(((Limit|Stop\\-Market|Market)\\-Order )?" - + "(Kauf" - + "|Buy" - + "|Verkauf" - + "|Sparplanausf.hrung" - + "|SAVINGS PLAN" - + "|Ex.cution de l.investissement programm.) .*" - + "|REINVESTIERUNG)", - "(ABRECHNUNG CRYPTOGESCH.FT" - + "|CRYPTO SPARPLAN)"); + DocumentType type = new DocumentType("(WERTPAPIERABRECHNUNG" // + + "|WERTPAPIERABRECHNUNG SPARPLAN" // + + "|SECURITIES SETTLEMENT SAVINGS PLAN" // + + "|SECURITIES SETTLEMENT" // + + "|REINVESTIERUNG" // + + "|INVESTISSEMENT)", // + "(ABRECHNUNG CRYPTOGESCH.FT|CRYPTO SPARPLAN)"); this.addDocumentTyp(type); Transaction pdfTransaction = new Transaction<>(); - Block firstRelevantLine = new Block("(((Limit|Stop\\-Market|Market)\\-Order )?" - + "(Kauf" - + "|Buy" - + "|Verkauf" - + "|Sparplanausf.hrung" - + "|SAVINGS PLAN" - + "|Ex.cution de l.investissement programm.) .*" - + "|REINVESTIERUNG)"); + Block firstRelevantLine = new Block("^TRADE REPUBLIC BANK GMBH .*$"); type.addBlock(firstRelevantLine); firstRelevantLine.set(pdfTransaction); pdfTransaction // - .subject(() -> { - BuySellEntry portfolioTransaction = new BuySellEntry(); - portfolioTransaction.setType(PortfolioTransaction.Type.BUY); - return portfolioTransaction; - }) - - // Is type --> "Verkauf" change from BUY to SELL - .section("type").optional() - .match("^((Limit|Stop\\-Market|Market)\\-Order )?" - + "(?(Kauf" - + "|Buy" - + "|Verkauf" - + "|Sparplanausf.hrung" - + "|SAVINGS PLAN" - + "|Ex.cution de l.investissement programm." - + "|REINVESTIERUNG))" - + " .*$") - .assign((t, v) -> { - if ("Verkauf".equals(v.get("type"))) - t.setType(PortfolioTransaction.Type.SELL); - }) - - .oneOf( - // @formatter:off - // Clinuvel Pharmaceuticals Ltd. 80 Stk. 22,82 EUR 1.825,60 EUR - // Registered Shares o.N. - // AU000000CUV3 - // ISIN: DE000A3H23V7 - // @formatter:on - section -> section - .attributes("name", "currency", "isin", "nameContinued") - .match("^(?.*) [\\.,\\d]+ (Stk\\.|titre\\(s\\)|Pcs\\.) [\\.,\\d]+ (?[\\w]{3}) [\\.,\\d]+ [\\w]{3}$") - .match("^(?.*)$") - .match("^(ISIN([\\s])?:([\\s])?)?(?[A-Z]{2}[A-Z0-9]{9}[0-9])$") - .assign((t, v) -> t.setSecurity(getOrCreateSecurity(v))) - , - - // This is for the reinvestment of dividends - // We pick the second - - // @formatter:off - // 1 Reinvestierung Vodafone Group PLC 699 Stk. - // 2 Reinvestierung Vodafone Group PLC 22 Stk. - // Registered Shares DL 0,2095238 - // GB00BH4HKS39 - // 1 Bruttoertrag 26,80 GBP - // 2 Barausgleich 0,37 GBP - // @formatter:on - section -> section - .attributes("name", "nameContinued", "isin", "currency") - .match("^[\\d] Reinvestierung .* [\\.,\\d]+ Stk\\.$") - .match("^[\\d] Reinvestierung (?.*) [\\.,\\d]+ Stk\\.$") - .match("^(?.*)$") - .match("^(?[A-Z]{2}[A-Z0-9]{9}[0-9])$") - .match("^[\\d] Bruttoertrag [\\.,\\d]+ (?[\\w]{3})$") - .assign((t, v) -> t.setSecurity(getOrCreateSecurity(v))) - ) - - .oneOf( - // @formatter:off - // Clinuvel Pharmaceuticals Ltd. 80 Stk. 22,82 EUR 1.825,60 EUR - // Tencent Holdings Ltd. 0,3773 titre(s) 53,00 EUR 20,00 EUR - // @formatter:on - section -> section - .attributes("shares") - .match("^.* (?[\\.,\\d]+) (Stk\\.|titre\\(s\\)) .*$") - .assign((t, v) -> t.setShares(asShares(v.get("shares")))) - , - // @formatter:off - // Berkshire Hathaway Inc. 0.3367 Pcs. 297.00 EUR 100.00 EUR - // @formatter:on - section -> section - .attributes("shares") - .match("^.* (?[\\.,\\d]+) Pcs\\. .*$") - .assign((t, v) -> t.setShares(asShares(v.get("shares"), "en", "US"))) - , - // @formatter:off - // 1 Reinvestierung Vodafone Group PLC 699 Stk. - // 2 Reinvestierung Vodafone Group PLC 22 Stk. - // @formatter:on - section -> section - .attributes("shares") - .match("^[\\d] Reinvestierung (?.*) [\\.,\\d]+ Stk\\.$") - .match("^[\\d] Reinvestierung (?.*) (?[\\.,\\d]+) Stk\\.$") - .assign((t, v) -> t.setShares(asShares(v.get("shares")))) - ) - - .oneOf( - // @formatter:off - // Market-Order Verkauf am 18.06.2019, um 17:50 Uhr an der Lang & Schwarz Exchange. - // Stop-Market-Order Verkauf am 10.06.2020, um 11:42 Uhr. - // Limit-Order Verkauf am 21.07.2020, um 09:30 Uhr an der Lang & Schwarz Exchange. - // Limit-Order Buy on 28.04.2023 at 11:13 (Europe/Berlin). - // Verkauf am 26.02.2021, um 11:44 Uhr. - // @formatter:on - section -> section - .attributes("date", "time") - .match("^((Limit|Stop\\-Market|Market)\\-Order )?(Kauf|Buy|Verkauf) .* (?([\\d]{2}\\.[\\d]{2}\\.[\\d]{4}|[\\d]{4}\\-[\\d]{2}\\-[\\d]{2}))(,)? (um|at) (?