diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf.json b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf.json index 9acb1fc4fc..7b1f201d05 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf.json +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf.json @@ -11,7 +11,8 @@ "security": { "name": "BASF SE", "isin": "DE000BASF111", - "wkn": "BASF11" + "wkn": "BASF11", + "currency": "EUR" }, "units": [ { diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf2.json b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf2.json index 6dc73de846..3f293a946d 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf2.json +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf2.json @@ -11,7 +11,8 @@ "security": { "name": "BASF SE", "isin": "DE000BASF111", - "wkn": "BASF11" + "wkn": "BASF11", + "currency": "EUR" }, "units": [ { diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf3.json b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf3.json index 79827eb4d0..afb01be0fe 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf3.json +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankKauf3.json @@ -10,7 +10,8 @@ "security": { "name": "COMSTAGE-MSCI WORLD TRN U.ETF INH.ANT.I O.N. 1/1", "isin": "LU0392494562", - "wkn": "ETF110" + "wkn": "ETF110", + "currency": "EUR" } } ] diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf.json b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf.json index 4ebea2dc7e..b1fcbc94d9 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf.json +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf.json @@ -11,7 +11,8 @@ "security": { "name": "BASF SE", "isin": "DE000BASF111", - "wkn": "BASF11" + "wkn": "BASF11", + "currency": "EUR" }, "units": [ { diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf2.json b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf2.json index b77ada2923..4924a15736 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf2.json +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf2.json @@ -11,7 +11,8 @@ "security": { "name": "BASF SE", "isin": "DE000BASF111", - "wkn": "BASF11" + "wkn": "BASF11", + "currency": "EUR" }, "units": [ { diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf3.json b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf3.json index 9fcfc767b6..4168ce2330 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf3.json +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/deutschebank/DeutscheBankVerkauf3.json @@ -11,7 +11,8 @@ "security": { "name": "BASF SE", "isin": "DE000BASF111", - "wkn": "BASF11" + "wkn": "BASF11", + "currency": "EUR" }, "units": [ { diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/ffb/FFB_Kauf01.json b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/ffb/FFB_Kauf01.json index a537193595..42166546df 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/ffb/FFB_Kauf01.json +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/ffb/FFB_Kauf01.json @@ -10,7 +10,8 @@ "security": { "name": "UBS Msci Pacific exJap.U ETF A", "isin": "LU0446734526", - "wkn": "A0X97T" + "wkn": "A0X97T", + "currency": "USD" }, "units": [ { @@ -35,7 +36,8 @@ "security": { "name": "ISHS Gbl.Corp.Bd.EU Hgd.U.ETF", "isin": "IE00B9M6SJ31", - "wkn": "A1W02Q" + "wkn": "A1W02Q", + "currency": "EUR" }, "units": [ { diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicDividende01.json b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicDividende01.json new file mode 100644 index 0000000000..8872c93ab4 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicDividende01.json @@ -0,0 +1,39 @@ +{ + "version": 1, + "transactions": [ + { + "type": "DIVIDEND", + "date": "2019-09-12", + "currency": "EUR", + "amount": 3.1, + "shares": 10.0, + "security": { + "name": "Microsoft Corp.", + "isin": "US5949181045", + "currency": "USD" + }, + "units": [ + { + "type": "GROSS_VALUE", + "fxAmount": 4.6, + "fxCurrency": "USD", + "fxRateToBase": 1.106 + }, + { + "type": "TAX", + "amount": 0.42 + }, + { + "type": "TAX", + "amount": 0.02 + }, + { + "type": "TAX", + "fxAmount": 0.69, + "fxCurrency": "USD", + "fxRateToBase": 1.106 + } + ] + } + ] +} diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicDividende01.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicDividende01.txt new file mode 100644 index 0000000000..9f7af94b63 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/traderepublic/TradeRepublicDividende01.txt @@ -0,0 +1,34 @@ +PDF Author: '' +PDFBox Version: 1.8.16 +----------------------------------------- +TRADE REPUBLIC BANK GMBH KASTANIENALLEE 32 10435 BERLIN +My Name SEITE 1 von 1 +My Str. 2 DATUM 12.09.2019 +D 12345 Berlin DEPOT XXXXXXXXX +DIVIDENDE +ÜBERSICHT +Dividende mit dem Ex-Tag 14.08.2019. +POSITION ANZAHL ERTRÄGNIS BETRAG +Microsoft Corp. 10 Stk. 0,460 USD 4,60 USD +Registered Shares DL-,00000625 +US5949181045 +GESAMT 4,60 USD +ABRECHNUNG +POSITION BETRAG +Quellensteuer DE für US-Emittent -0,690 USD +Zwischensumme 3,91 USD +Zwischensumme 1,106 EUR/USD 3,54 EUR +Kapitalertragssteuer -0,420 EUR +Solidaritätszuschlag -0,020 EUR +GESAMT 3,10 EUR +BUCHUNG +VERRECHNUNGSKONTO VALUTA BETRAG +DE63110XXXXXXXXXXXXXXX 12.09.2019 3,10 EUR +Microsoft Corp. Registered Shares DL-,00000625 in Girosammelverwahrung. +Diese Abrechnung wird maschinell erstellt und daher nicht unterschrieben. +Sofern keine Umsatzsteuer ausgewiesen ist, handelt es sich gem. § 4 Nr. 8 UStG um eine umsatzsteuerfreie +Leistung. +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 Ingo Hillen +10435 Berlin USt-ID DE307510626 Karsten Müller +ABRE / 12.09.2019 / 363XXXXX / XXXX-XXXX \ No newline at end of file diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/JSONPDFExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/JSONPDFExtractor.java index a7cbf1626e..e0db14803a 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/JSONPDFExtractor.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/JSONPDFExtractor.java @@ -34,9 +34,11 @@ import name.abuchen.portfolio.json.JSecurity; import name.abuchen.portfolio.json.JTransaction; import name.abuchen.portfolio.json.JTransactionUnit; +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; import name.abuchen.portfolio.money.Money; import name.abuchen.portfolio.money.Values; @@ -97,6 +99,9 @@ private void addTransaction() case SALE: pdftx.wrap(t -> wrapBuySell(t, PortfolioTransaction.Type.SELL)); break; + case DIVIDEND: + pdftx.wrap(this::wrapDividend); + break; default: throw new IllegalArgumentException(); } @@ -160,6 +165,7 @@ private void setValuesToSecurity(JTransaction t, Map v) security.setIsin(v.get("isin")); //$NON-NLS-1$ security.setTicker(v.get("ticker")); //$NON-NLS-1$ security.setWkn(v.get("wkn")); //$NON-NLS-1$ + security.setCurrency(asCurrencyCode(v.get("currency"))); //$NON-NLS-1$ t.setSecurity(security); } @@ -232,12 +238,7 @@ private Extractor.Item wrapBuySell(JTransaction t, PortfolioTransaction.Type txT entry.setShares(Values.Share.factorize(t.getShares())); - Map values = new HashMap<>(); - values.put("name", t.getSecurity().getName()); //$NON-NLS-1$ - values.put("isin", t.getSecurity().getIsin()); //$NON-NLS-1$ - values.put("tickerSymbol", t.getSecurity().getTicker()); //$NON-NLS-1$ - values.put("wkn", t.getSecurity().getWkn()); //$NON-NLS-1$ - entry.setSecurity(getOrCreateSecurity(values)); + entry.setSecurity(convertToSecurity(t)); t.getUnits().map(u -> convertToUnit(t, u)).filter(Objects::nonNull) .forEach(u -> entry.getPortfolioTransaction().addUnit(u)); @@ -247,12 +248,62 @@ private Extractor.Item wrapBuySell(JTransaction t, PortfolioTransaction.Type txT return item; } + private Extractor.Item wrapDividend(JTransaction t) + { + AccountTransaction tx = new AccountTransaction(); + tx.setType(AccountTransaction.Type.DIVIDENDS); + + tx.setAmount(Values.Amount.factorize(t.getAmount())); + tx.setCurrencyCode(t.getCurrency()); + tx.setShares(Values.Share.factorize(t.getShares())); + + if (t.getTime() != null) + tx.setDateTime(t.getDate().atTime(t.getTime())); + else + tx.setDateTime(t.getDate().atStartOfDay()); + + tx.setSecurity(convertToSecurity(t)); + + t.getUnits().map(u -> convertToUnit(t, u)).filter(Objects::nonNull).forEach(tx::addUnit); + + TransactionItem item = new TransactionItem(tx); + item.setData(t); + return item; + } + + private Security convertToSecurity(JTransaction t) + { + Map values = new HashMap<>(); + values.put("name", t.getSecurity().getName()); //$NON-NLS-1$ + values.put("isin", t.getSecurity().getIsin()); //$NON-NLS-1$ + values.put("tickerSymbol", t.getSecurity().getTicker()); //$NON-NLS-1$ + values.put("wkn", t.getSecurity().getWkn()); //$NON-NLS-1$ + values.put("currency", t.getSecurity().getCurrency()); //$NON-NLS-1$ + return getOrCreateSecurity(values); + } + private Transaction.Unit convertToUnit(JTransaction jtx, JTransactionUnit junit) { - if (junit.getAmount() == 0d) - return null; + Money amount = null; + + if (junit.getAmount() == null || junit.getAmount() == 0d) + { + // if amount is not available, but fxAmount and fxRateToBase is, + // calculate the value + if (junit.getFxAmount() == null || junit.getFxAmount() == 0d // + || junit.getFxRateToBase() == null + || junit.getFxRateToBase().compareTo(BigDecimal.ZERO) == 0) + return null; + + double value = BigDecimal.valueOf(junit.getFxAmount()) + .divide(junit.getFxRateToBase(), 2, RoundingMode.HALF_DOWN).doubleValue(); - Money amount = Money.of(jtx.getCurrency(), Values.Amount.factorize(junit.getAmount())); + amount = Money.of(jtx.getCurrency(), Values.Amount.factorize(value)); + } + else + { + amount = Money.of(jtx.getCurrency(), Values.Amount.factorize(junit.getAmount())); + } if (junit.getType() != Transaction.Unit.Type.GROSS_VALUE && (junit.getFxAmount() == null || junit.getFxAmount() == 0d)) @@ -262,7 +313,7 @@ private Transaction.Unit convertToUnit(JTransaction jtx, JTransactionUnit junit) if (Strings.isNullOrEmpty(junit.getFxCurrency())) return null; - String fxCurrency = asCurrencyCode(junit.getFxCurrency()); + String fxCurrency = asCurrencyCode(jtx.getSecurity().getCurrency()); if (jtx.getCurrency().equals(fxCurrency)) { diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/PDFImportAssistant.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/PDFImportAssistant.java index 6300da2773..64fbcf9566 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/PDFImportAssistant.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/PDFImportAssistant.java @@ -55,6 +55,7 @@ public PDFImportAssistant(Client client, List files) extractors.add(new JSONPDFExtractor(client, "deutsche-bank-purchase.json")); //$NON-NLS-1$ extractors.add(new JSONPDFExtractor(client, "deutsche-bank-sale.json")); //$NON-NLS-1$ extractors.add(new JSONPDFExtractor(client, "ffb-purchase.json")); //$NON-NLS-1$ + extractors.add(new JSONPDFExtractor(client, "trade-republic-dividends.json")); //$NON-NLS-1$ } public Map> run(IProgressMonitor monitor, Map> errors) diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ffb-purchase.json b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ffb-purchase.json index 5b39fff2b1..42a65a69c6 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ffb-purchase.json +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ffb-purchase.json @@ -14,7 +14,7 @@ { "context": "SECURITY", "pattern": [ - "^Splittkauf( Betrag)? (?.*) [\\d.,]+ \\w{3} [\\d.,]+ \\w{3} [\\d.,]+$", + "^Splittkauf( Betrag)? (?.*) [\\d.,]+ \\w{3} [\\d.,]+ (?\\w{3}) [\\d.,]+$", "^[\\d]* (?[^ ]+) / (?[^ ]+) .*" ] }, diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/trade-republic-dividends.json b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/trade-republic-dividends.json new file mode 100644 index 0000000000..6ba3403a74 --- /dev/null +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/trade-republic-dividends.json @@ -0,0 +1,86 @@ +{ + "version": 1, + "name": "Deutsche Bank - Kaufbuchungen", + "locale": "de", + "pattern": [ + "TRADE REPUBLIC", + "DIVIDENDE" + ], + "transactions": [ + { + "type": "DIVIDEND", + "startWith": "DIVIDENDE", + "sections": [ + { + "context": "SECURITY", + "pattern": [ + "POSITION ANZAHL ERTRÄGNIS BETRAG", + "(?.*) ([\\d+,.]*) Stk. ([\\d+,.]*) (?\\w{3}+) ([\\d+,.]*) (\\w{3}+)$", + ".*", + "(?.*)" + ] + }, + { + "pattern": [ + "GESAMT ([\\d+,.]*) (\\w{3}+)", + "GESAMT (?[\\d+,.]*) (?\\w{3}+)" + ] + }, + { + "pattern": [ + "VERRECHNUNGSKONTO VALUTA BETRAG", + ".* (?\\d+.\\d+.\\d{4}+) ([\\d+,.]*) (\\w{3}+)" + ] + }, + { + "pattern": [ + "POSITION ANZAHL ERTRÄGNIS BETRAG", + "(.*) (?[\\d+,.]*) Stk. ([\\d+,.]*) (\\w{3}+) ([\\d+,.]*) (\\w{3}+)$" + ] + }, + { + "context": "UNIT", + "isOptional": true, + "pattern": [ + "GESAMT (?[\\d+,.]*) (?\\w{3}+)", + "Zwischensumme (?[\\d.,]+) \\w{3}+/\\w{3}+ [\\d.,]+ \\w{3}+" + ], + "attributes": { + "type": "GROSS_VALUE" + } + }, + { + "context": "UNIT", + "isOptional": true, + "pattern": [ + "Kapitalertragssteuer -(?[\\d.,]+) (?\\w{3}+)" + ], + "attributes": { + "type": "TAX" + } + }, + { + "context": "UNIT", + "isOptional": true, + "pattern": [ + "Solidaritätszuschlag -(?[\\d.,]+) (?\\w{3}+)" + ], + "attributes": { + "type": "TAX" + } + }, + { + "context": "UNIT", + "isOptional": true, + "pattern": [ + "Quellensteuer DE für US-Emittent -(?[\\d.,]+) (?\\w{3}+)", + "Zwischensumme (?[\\d.,]+) \\w{3}+/\\w{3}+ [\\d.,]+ \\w{3}+" + ], + "attributes": { + "type": "TAX" + } + } + ] + } + ] +} diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/json/JSecurity.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/json/JSecurity.java index 4e4f6fdc25..23ba469976 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/json/JSecurity.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/json/JSecurity.java @@ -10,6 +10,7 @@ public class JSecurity private String isin; private String wkn; private String ticker; + private String currency; public String getName() { @@ -50,6 +51,16 @@ public void setTicker(String ticker) { this.ticker = ticker; } + + public String getCurrency() + { + return currency; + } + + public void setCurrency(String currency) + { + this.currency = currency; + } public static JSecurity from(Security security) { @@ -58,6 +69,7 @@ public static JSecurity from(Security security) s.isin = Strings.emptyToNull(security.getIsin()); s.wkn = Strings.emptyToNull(security.getWkn()); s.ticker = Strings.emptyToNull(security.getTickerSymbol()); + s.currency = Strings.emptyToNull(security.getCurrencyCode()); return s; } } diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/json/JTransactionUnit.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/json/JTransactionUnit.java index 9bb24b89a7..e2af94b663 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/json/JTransactionUnit.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/json/JTransactionUnit.java @@ -9,7 +9,7 @@ public class JTransactionUnit { private Transaction.Unit.Type type; - private double amount; + private Double amount; private String fxCurrency; private Double fxAmount; private BigDecimal fxRateToBase; @@ -24,12 +24,12 @@ public void setType(Transaction.Unit.Type type) this.type = type; } - public double getAmount() + public Double getAmount() { return amount; } - public void setAmount(double amount) + public void setAmount(Double amount) { this.amount = amount; }