From 68bff777018ce53bcc817ebe91b6b452f2b2c129 Mon Sep 17 00:00:00 2001 From: Alexander Ott <45203494+Nirus2000@users.noreply.github.com> Date: Thu, 2 Jan 2025 08:00:01 +0100 Subject: [PATCH] Modify Scalable Capita PDF-Importer to support new transaction (#4438) https://forum.portfolio-performance.info/t/pdf-import-von-baader-bank-scalable-capital-smartbroker-plus/2057/414 --- .../pdf/scalablecapital/Kauf02.txt | 27 +++++ .../ScalableCapitalPDFExtractorTest.java | 73 +++++++++++++- .../pdf/scalablecapital/Verkauf01.txt | 42 ++++++++ .../pdf/ScalableCapitalPDFExtractor.java | 98 ++++++++++++------- 4 files changed, 203 insertions(+), 37 deletions(-) create mode 100644 name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/Kauf02.txt create mode 100644 name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/Verkauf01.txt diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/Kauf02.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/Kauf02.txt new file mode 100644 index 0000000000..e2228dfef6 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/Kauf02.txt @@ -0,0 +1,27 @@ +PDFBox Version: 1.8.17 +Portfolio Performance Version: 0.73.0 +System: macosx | aarch64 | 21.0.5+11-LTS | Azul Systems, Inc. +----------------------------------------- +Scalable Capital GmbH • Seitzstraße 8e • 80538 München • Deutschland +rxJrK ThosSK +BwnmeQxDygxpHJ kiWlnE 33 +52347 YRyvGwLrLFzVO Datum 27.12.2024 +Deutschland Seite 1 / 1 +Wertpapierabrechnung +für Sparplanausführung +Typ LIMIT Order SCALx2qhYduKQJf +Ausführung 27.12.2024 11:46:01 Geschäft 4086GZHYi7421537 +Ausführungsplatz EIX Lagerland Deutschland +Depot 7684756394 Verwahrart Girosammelverwahrung +Wertpapierabrechnung +Typ Wertpapier Anzahl Kurs Betrag +Kauf American Water Works 0,016515 Stk. 121,10 EUR 2,00 EUR +US0304201033 +Total 2,00 EUR +Der Betrag wird mit dem Verrechnungskonto DEghin3u4DSCVJ09 (Valuta: 31.12.2024) verrechnet. +Bitte überprüfen Sie die Informationen auf Richtigkeit und melden Sie etwaige Einwände unverzüglich bei uns. +Verwenden Sie dafür den Menüpunkt Support im Kundenbereich. +Scalable Capital GmbH HRB 217778 Geschäftsführer: Aufsichtsrat: Seite +Seitzstraße 8e Amtsgericht München Erik Podzuweit, Florian Prucker Patrick Olson (Vorsitzender) +80538 München USt.-Id. Nr.: DE300434774 Martin Krebs, Dirk Franzmeyer, Dirk +Urmoneit 1 / 1 \ No newline at end of file diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/ScalableCapitalPDFExtractorTest.java b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/ScalableCapitalPDFExtractorTest.java index 6362047f9a..16e56c0506 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/ScalableCapitalPDFExtractorTest.java +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/ScalableCapitalPDFExtractorTest.java @@ -11,7 +11,10 @@ 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; @@ -54,17 +57,81 @@ public void testKauf01() // check security assertThat(results, hasItem(security( // - hasIsin("IE0008T6IUX0"), // + hasIsin("IE0008T6IUX0"), hasWkn(null), hasTicker(null), // hasName("Vngrd Fds-ESG Dv.As-Pc Al ETF"), // hasCurrencyCode("EUR")))); // check dividends transaction assertThat(results, hasItem(purchase( // - hasDate("2024-12-12T13:12:51"), hasShares(3), // + hasDate("2024-12-12T13:12:51"), hasShares(3.00), // hasSource("Kauf01.txt"), // - hasNote(null), // + hasNote("Ord.-Nr.: SCALsin78vS5CYz"), // hasAmount("EUR", 19.49), hasGrossValue("EUR", 18.50), // hasTaxes("EUR", 0.00), hasFees("EUR", 0.99)))); } + + @Test + public void testKauf02() + { + ScalableCapitalPDFExtractor extractor = new ScalableCapitalPDFExtractor(new Client()); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Kauf02.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("US0304201033"), hasWkn(null), hasTicker(null), // + hasName("American Water Works"), // + hasCurrencyCode("EUR")))); + + // check dividends transaction + assertThat(results, hasItem(purchase( // + hasDate("2024-12-27T11:46:01"), hasShares(0.016515), // + hasSource("Kauf02.txt"), // + hasNote("Ord.-Nr.: SCALx2qhYduKQJf"), // + hasAmount("EUR", 2.00), hasGrossValue("EUR", 2.00), // + hasTaxes("EUR", 0.00), hasFees("EUR", 0.00)))); + + } + + @Test + public void testVerkauf01() + { + ScalableCapitalPDFExtractor extractor = new ScalableCapitalPDFExtractor(new Client()); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Verkauf01.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("LU2903252349"), hasWkn(null), hasTicker(null), // + hasName("Scalable MSCI AC World Xtrackers (Acc)"), // + hasCurrencyCode("EUR")))); + + // check dividends transaction + assertThat(results, hasItem(sale( // + hasDate("2024-12-30T13:39:12"), hasShares(1.00), // + hasSource("Verkauf01.txt"), // + hasNote("Ord.-Nr.: SCALRnomPwYQrc5"), // + hasAmount("EUR", 8.60), hasGrossValue("EUR", 9.59), // + hasTaxes("EUR", 0.00), hasFees("EUR", 0.99)))); + + } } diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/Verkauf01.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/Verkauf01.txt new file mode 100644 index 0000000000..f72d0871f9 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/scalablecapital/Verkauf01.txt @@ -0,0 +1,42 @@ +PDFBox Version: 1.8.17 +Portfolio Performance Version: 0.73.0 +System: macosx | aarch64 | 21.0.5+11-LTS | Azul Systems, Inc. +----------------------------------------- +Scalable Capital GmbH • Seitzstraße 8e • 80538 München • Deutschland +xYXVd TlPyTs +OZleTFvjpBihGc HEJOhU 91 +91919 JdNDkTwZDNPEq Datum 30.12.2024 +Deutschland Seite 1 / 2 +Wertpapierabrechnung +für Kundenauftrag +Typ MARKET Order SCALRnomPwYQrc5 +Ausführung 30.12.2024 13:39:12 Geschäft 3050eskoFJ914634 +Ausführungsplatz EIX Lagerland Luxemburg +Depot 026394660 Verwahrart Wertpapierrechnung +Wertpapierabrechnung +Typ Wertpapier Anzahl Kurs Betrag +Verkauf Scalable MSCI AC World Xtrackers (Acc) 1,00 Stk. 9,585 EUR 9,59 EUR +LU2903252349 +Ordergebühren -0,99 EUR +Total 8,60 EUR +Der Betrag wird mit dem Verrechnungskonto DE2634edjfbvdcgD27 (Valuta: 02.01.2025) verrechnet. +Bitte überprüfen Sie die Informationen auf Richtigkeit und melden Sie etwaige Einwände unverzüglich bei uns. +Verwenden Sie dafür den Menüpunkt Support im Kundenbereich. +Scalable Capital GmbH HRB 217778 Geschäftsführer: Aufsichtsrat: Seite +Seitzstraße 8e Amtsgericht München Erik Podzuweit, Florian Prucker Patrick Olson (Vorsitzender) +80538 München USt.-Id. Nr.: DE300434774 Martin Krebs, Dirk Franzmeyer, Dirk +Urmoneit 1 / 2 +Wertpapierabrechnung +Verkauf 1,00 Stk. Scalable MSCI AC World Xtrackers +(Acc) +Ermittlung steuerrelevanter Erträge +Typ Anmerkung Betrag +Gewinn oder Verlust -0,08 EUR +Berücksichtigte Ordergebühren -1,98 EUR +Teilfreistellung 30 % +0,62 EUR +Verlusttopf allgemein 2,24 EUR → 3,68 EUR +1,44 EUR +Zu versteuern 0,00 EUR +Scalable Capital GmbH HRB 217778 Geschäftsführer: Aufsichtsrat: Seite +Seitzstraße 8e Amtsgericht München Erik Podzuweit, Florian Prucker Patrick Olson (Vorsitzender) +80538 München USt.-Id. Nr.: DE300434774 Martin Krebs, Dirk Franzmeyer, Dirk +Urmoneit 2 / 2 \ No newline at end of file diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ScalableCapitalPDFExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ScalableCapitalPDFExtractor.java index 1a7b799a2d..a8e6fc1351 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ScalableCapitalPDFExtractor.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ScalableCapitalPDFExtractor.java @@ -1,13 +1,13 @@ package name.abuchen.portfolio.datatransfer.pdf; +import static name.abuchen.portfolio.util.TextUtil.trim; + 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.BuySellEntry; import name.abuchen.portfolio.model.Client; import name.abuchen.portfolio.model.PortfolioTransaction; -import name.abuchen.portfolio.model.Transaction.Unit; -import name.abuchen.portfolio.money.Money; @SuppressWarnings("nls") public class ScalableCapitalPDFExtractor extends AbstractPDFExtractor @@ -24,18 +24,21 @@ public ScalableCapitalPDFExtractor(Client client) @Override public String getLabel() { - return "Scalable Capital"; + return "Scalable Capital GmbH"; } private void addPurchaseTransaction() { final DocumentType type = new DocumentType("Wertpapierabrechnung"); - this.addDocumentTyp(type); - Block purchase = new Block(".* Kundenauftrag.*"); - type.addBlock(purchase); - purchase.set(new Transaction() + Transaction pdfTransaction = new Transaction<>(); + + Block firstRelevantLine = new Block("^f.r (Kundenauftrag|Sparplanausf.hrung) .*$"); + type.addBlock(firstRelevantLine); + firstRelevantLine.set(pdfTransaction); + + pdfTransaction // .subject(() -> { BuySellEntry portfolioTransaction = new BuySellEntry(); @@ -43,44 +46,71 @@ private void addPurchaseTransaction() return portfolioTransaction; }) + // Is type --> "Verkauf" change from BUY to SELL + .section("type").optional() // + .match("^(?(Kauf|Verkauf)) .* [\\.,\\d]+ Stk\\. .*$") // + .assign((t, v) -> { + if ("Verkauf".equals(v.get("type"))) // + t.setType(PortfolioTransaction.Type.SELL); + }) + + // @formatter:off + // Kauf Vngrd Fds-ESG Dv.As-Pc Al ETF 3,00 Stk. 6,168 EUR 18,50 EUR + // Verkauf Scalable MSCI AC World Xtrackers (Acc) 1,00 Stk. 9,585 EUR 9,59 EUR + // IE0008T6IUX0 + // @formatter:on .section("name", "currency", "isin") // - .find("Typ Wertpapier Anzahl Kurs Betrag") // - .match("^Kauf (?.*) " // - + "[.,\\d]+ Stk. " // - + "[.,\\d]+ [A-Z]{3} " // - + "[.,\\d]+ (?[A-Z]{3})") + .match("^(Kauf|Verkauf) (?.*) [\\.,\\d]+ Stk\\. [\\.,\\d]+ (?[\\w]{3}) [\\.,\\d]+ [\\w]{3}$") // .match("^(?[A-Z]{2}[A-Z0-9]{9}[0-9])$") // .assign((t, v) -> t.setSecurity(getOrCreateSecurity(v))) - .section("shares", "amount", "currency") // - .find("Typ Wertpapier Anzahl Kurs Betrag") // - .match("^Kauf .* " // - + "(?[.,\\d]+) Stk. " // - + "[.,\\d]+ [A-Z]{3} " // - + "(?[.,\\d]+) (?[A-Z]{3})") + // @formatter:off + // Kauf Vngrd Fds-ESG Dv.As-Pc Al ETF 3,00 Stk. 6,168 EUR 18,50 EUR + // Verkauf Scalable MSCI AC World Xtrackers (Acc) 1,00 Stk. 9,585 EUR 9,59 EUR + // @formatter:on + .section("shares") // + .match("^(Kauf|Verkauf) .* (?[\\.,\\d]+) Stk\\. [\\.,\\d]+ [\\w]{3} [\\.,\\d]+ [\\w]{3}$") // + .assign((t, v) -> t.setShares(asShares(v.get("shares")))) + + // @formatter:off + // Ausführung 12.12.2024 13:12:51 Geschäft 36581526 + // @formatter:on + .section("date", "time") // + .match("^Ausf.hrung (?[\\d]{2}\\.[\\w]{2}\\.[\\d]{4}) (?