From 5f7d8fdf8f4db5bca56d97382bf886689a984097 Mon Sep 17 00:00:00 2001 From: Christian Kaufmann Date: Thu, 3 Aug 2023 11:31:48 +0200 Subject: [PATCH] Fix Quirion dividend import in USD Issue: #3474 Signed-off-by: Christian Kaufmann [rebased to master] Signed-off-by: Andreas Buchen --- .../pdf/quirinbankag/Dividende04.txt | 72 +++++++++++++++++++ .../QuirinPrivatbankAGPDFExtractorTest.java | 46 ++++++++++++ .../pdf/QuirinBankAGPDFExtractor.java | 43 ++++++++--- 3 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/quirinbankag/Dividende04.txt diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/quirinbankag/Dividende04.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/quirinbankag/Dividende04.txt new file mode 100644 index 0000000000..d9fcc40149 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/quirinbankag/Dividende04.txt @@ -0,0 +1,72 @@ +``` +PDFBox Version: 1.8.17 +Portfolio Performance Version: 0.64.4 +----------------------------------------- +Erträgnisabrechnung +Referenz-Nr 12345858 +Datum 28.07.2023 +Depot 1234567800 +Muster, Hans +Frau +Hans Muster +Straße 2 +12345 Berlin +Seite 1 von 2 +Für aus Ihrem Depot fällig gewordene Erträgnisse erteilen wir nachstehende Abrechnung: +Wertpapierbezeichnung iShsIII-MSCI EM Sm.Cap U.ETF Registered Shares o.N. +ISIN IE00B3F81G20 +WKN A0RGER +Verwahrart Wertpapierrechnung +Lagerland Irland +Nominal/Stück 1,9983 ST +Währung USD +Zahlungszeitraum 01.07.2023 - 30.06.2024 +Ausschüttung USD 0,7849 pro Anteil +Ex-Tag 13.07.2023 +Zahlungstag 26.07.2023 +Betrag USD 1,57 +Kapitalertragsteuer USD 0,00 +Solidaritätszuschlag USD 0,00 +Kirchensteuer USD 0,00 +Ausmachender Betrag USD 1,57 +Devisenkurs EUR/USD 1,110890 +Ausmachender Betrag EUR 1,41 +Der Abrechnungsbetrag wird mit Valuta 26.07.2023 über Ihr Konto 1234567800 EUR gebucht. +Gebietsansässigen Empfängern von Erträgen aus ausländischen Wertpapieren obliegt eine Meldepflicht nach §§ 67 +ff. AWV (Außenwirtschaftsverordnung), wenn die Gutschrift EUR 12.500,00 übersteigt. +Keine Steuerbescheinigung! +Für weitere Fragen wenden Sie sich bitte an Ihren Kundenberater. +Diese Mitteilung wurde maschinell erstellt und wird von der Bank nicht unterschrieben. +Quirin Privatbank AG +Postfach 311105 | 10641 Berlin T +49 (0)30 890 21-300 Handelsregister: Vorstand: Karl Matthäus Schmidt +Kurfürstendamm 119 | 10711 Berlin F +49 (0)30 890 21-301 Berlin Charlottenburg, HRB 87859 Johannes Eismann +www.quirinprivatbank.de info@quirinprivatbank.de USt-IdNr.: DE195661729 Aufsichtsratsvorsitzender: Holger Timm +SECTRX2 / 62243624 / 20230728 14:36:14 +Erträgnisabrechnung +Referenz-Nr 12345858 +Seite 2 von 2 +Steuerliche Informationen +Steuerlicher Devisenumrechnungskurs: EUR/USD 1,110890 +Ausschüttungsbetrag: EUR 1,41 +Steuerpflichtiger Betrag nach Teilfreistellung im Privatvermögen: EUR 1,41 +Kapitalertragsteuerpflichtiger Betrag: EUR 1,41 +Stand allg. Verlustverrechnungstopf vor Veränderung: EUR 0,00 +Veränderung allg. Verlustverrechnungstopf: EUR 0,00 +Stand allg. Verlustverrechnungstopf nach Veränderung: EUR 0,00 +Stand Freistellungsauftrag vor Veränderung: EUR 16,52 +Veränderung Freistellungsauftrag: EUR -1,41 +Stand Freistellungsauftrag nach Veränderung: EUR 15,11 +Bemessungsgrundlage für Kapitalertragsteuer: EUR 0,00 +Kapitalertragsteuer: EUR 0,00 +Solidaritätszuschlag: EUR 0,00 +Kirchensteuer: EUR 0,00 +Steuerliche Information für Veranlagungszwecke +Steuerpfl. Betrag nach Teilfreistellung im Betriebsvermögen (EStG): EUR 1,41 +Steuerpfl. Betrag nach Teilfreistellung im Betriebsvermögen (KStG): EUR 1,41 +Quirin Privatbank AG +Postfach 311105 | 10641 Berlin T +49 (0)30 890 21-300 Handelsregister: Vorstand: Karl Matthäus Schmidt +Kurfürstendamm 119 | 10711 Berlin F +49 (0)30 890 21-301 Berlin Charlottenburg, HRB 87859 Johannes Eismann +www.quirinprivatbank.de info@quirinprivatbank.de USt-IdNr.: DE195661729 Aufsichtsratsvorsitzender: Holger Timm +SECTRX2 / 62243624 / 20230728 14:36:14 + +``` \ No newline at end of file diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/quirinbankag/QuirinPrivatbankAGPDFExtractorTest.java b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/quirinbankag/QuirinPrivatbankAGPDFExtractorTest.java index a534a7c2e7..6564a09226 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/quirinbankag/QuirinPrivatbankAGPDFExtractorTest.java +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/quirinbankag/QuirinPrivatbankAGPDFExtractorTest.java @@ -578,6 +578,52 @@ public void testDividende03() assertThat(grossValueUnit.getForex(), is(Money.of(CurrencyUnit.USD, Values.Amount.factorize(163.08)))); } + @Test + public void testDividende04() + { + QuirinBankAGPDFExtractor extractor = new QuirinBankAGPDFExtractor(new Client()); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Dividende04.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("IE00B3F81G20")); + assertThat(security.getWkn(), is("A0RGER")); + assertNull(security.getTickerSymbol()); + assertThat(security.getName(), is("iShsIII-MSCI EM Sm.Cap U.ETF Registered Shares o.N.")); + assertThat(security.getCurrencyCode(), is(CurrencyUnit.USD)); + + // check dividends transaction + AccountTransaction transaction = (AccountTransaction) results.stream().filter(TransactionItem.class::isInstance) + .findFirst().orElseThrow(IllegalArgumentException::new).getSubject(); + + assertThat(transaction.getType(), is(AccountTransaction.Type.DIVIDENDS)); + + assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2023-07-26T00:00"))); + assertThat(transaction.getShares(), is(Values.Share.factorize(1.9983))); + assertThat(transaction.getSource(), is("Dividende04.txt")); + assertThat(transaction.getNote(), is("Referenz-Nr 12345858")); + + assertThat(transaction.getMonetaryAmount(), + is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1.41)))); + assertThat(transaction.getGrossValue(), + is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1.41)))); + 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)))); + + Unit grossValueUnit = transaction.getUnit(Unit.Type.GROSS_VALUE).orElseThrow(IllegalArgumentException::new); + assertThat(grossValueUnit.getForex(), is(Money.of(CurrencyUnit.USD, Values.Amount.factorize(1.57)))); + } + @Test public void testDividende03WithSecurityInEUR() { diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/QuirinBankAGPDFExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/QuirinBankAGPDFExtractor.java index eb72180d8e..8a5560e615 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/QuirinBankAGPDFExtractor.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/QuirinBankAGPDFExtractor.java @@ -102,7 +102,7 @@ private void addBuySellTransaction_Format01() return null; }); - addTaxesSectionsTransaction(pdfTransaction, type); + addTaxesSectionsTransactionFormat02(pdfTransaction, type); addFeesSectionsTransaction(pdfTransaction, type); } @@ -220,7 +220,7 @@ private void addBuySellTransaction_Format02() return null; }); - addTaxesSectionsTransaction(pdfTransaction, type); + addTaxesSectionsTransactionFormat02(pdfTransaction, type); addFeesSectionsTransaction(pdfTransaction, type); } @@ -267,13 +267,14 @@ private void addDividendeTransaction_Format01() t.setAmount(asAmount(v.get("amount"))); }) - // Dividenden für 01.01.2009-31.12.2009 Bruttobetrag 163,08 USD 124,50 EUR - // Devisenkurs 1,309900 + // Devisenkurs EUR/USD 1,110890 .section("baseCurrency", "termCurrency", "exchangeRate", "fxGross", "fxCurrency", "gross", "currency").optional() - .match("^(Umrechnungskurs|Exchange Rate): (?[\\w]{3})\\/(?[\\w]{3}) (?[\\.,\\d]+)$") - .match("^(Bruttobetrag|Gross Amount) (?[\\w]{3}) (?[\\.,\\d]+)$") - .match("^(Bruttobetrag|Gross Amount) (?[\\w]{3}) (?[\\.,\\d]+)$") + .match("^(Ausmachender Betrag) (?[\\w]{3}) (?[\\.,\\d]+)$") + .match("^(Devisenkurs) (?[\\w]{3})\\/(?[\\w]{3}) (?[\\.,\\d]+)$") + .match("^Ausmachender Betrag (?[\\w]{3}) (?[\\.,\\d]+)$") .assign((t, v) -> { + t.setCurrencyCode(asCurrencyCode(v.get("currency"))); + t.setAmount(asAmount(v.get("gross"))); ExtrExchangeRate rate = asExchangeRate(v); type.getCurrentContext().putType(rate); @@ -294,7 +295,7 @@ private void addDividendeTransaction_Format01() return null; }); - addTaxesSectionsTransaction(pdfTransaction, type); + addTaxesSectionsTransactionFormat01(pdfTransaction, type); addFeesSectionsTransaction(pdfTransaction, type); block.set(pdfTransaction); @@ -399,7 +400,7 @@ private void addDividendeTransaction_Format02() return null; }); - addTaxesSectionsTransaction(pdfTransaction, type); + addTaxesSectionsTransactionFormat02(pdfTransaction, type); addFeesSectionsTransaction(pdfTransaction, type); block.set(pdfTransaction); @@ -689,7 +690,29 @@ private void addDepotStatementTransaction() })); } - private > void addTaxesSectionsTransaction(T transaction, DocumentType type) + private > void addTaxesSectionsTransactionFormat01(T transaction, DocumentType type) + { + transaction + // Kapitalertragsteuer EUR - 752,05 + // Kapitalertragsteuer: EUR -73,71 + .section("currency", "tax").optional() + .match("^Kapitalertragsteuer: (?[\\w]{3}) \\-(?[\\.,\\d]+)$") + .assign((t, v) -> processTaxEntries(t, v, type)) + + // Solidaritätszuschlag EUR - 41,36 + // Solidaritätszuschlag: EUR -4,05 + .section("currency", "tax").optional() + .match("^Solidarit.tszuschlag: (?[\\w]{3}) \\-(?[\\.,\\d]+)$") + .assign((t, v) -> processTaxEntries(t, v, type)) + + // Kirchensteuer EUR - 1,00 + // Kirchensteuer EUR: -1,00 + .section("currency", "tax").optional() + .match("^Kirchensteuer: (?[\\w]{3}) \\-(?[\\.,\\d]+)$") + .assign((t, v) -> processTaxEntries(t, v, type)); + } + + private > void addTaxesSectionsTransactionFormat02(T transaction, DocumentType type) { transaction // Ausl. Quellensteuer -32,62 USD -24,90 EUR