package name.abuchen.portfolio.datatransfer.pdf; import java.io.IOException; import java.math.BigDecimal; import name.abuchen.portfolio.Messages; 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.AccountTransaction; 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; import name.abuchen.portfolio.money.MutableMoney; public class DeutscheBankPDFExctractor extends AbstractPDFExtractor { public DeutscheBankPDFExctractor(Client client) throws IOException { super(client); addBuyTransaction(); addSellTransaction(); addDividendTransaction("Ertragsgutschrift"); //$NON-NLS-1$ addDividendTransaction("Dividendengutschrift"); //$NON-NLS-1$ } @SuppressWarnings("nls") private void addBuyTransaction() { DocumentType type = new DocumentType("Kauf von Wertpapieren"); this.addDocumentTyp(type); Block block = new Block("Abrechnung: Kauf von Wertpapieren"); type.addBlock(block); block.set(new Transaction<BuySellEntry>() .subject(() -> { BuySellEntry entry = new BuySellEntry(); entry.setType(PortfolioTransaction.Type.BUY); return entry; }) .section("wkn", "isin", "name", "currency") .find("Filialnummer Depotnummer Wertpapierbezeichnung Seite") // .match("^.{15}(?<name>.*)$") // .match("^WKN (?<wkn>[^ ]*) (.*)$") // .match("^ISIN (?<isin>[^ ]*) Kurs (?<currency>\\w{3}+) (.*)$") // .assign((t, v) -> { t.setSecurity(getOrCreateSecurity(v)); }) .section("shares") // .match("^WKN [^ ]* Nominal ST (?<shares>\\d+(,\\d+)?)") // .assign((t, v) -> t.setShares(asShares(v.get("shares")))) .section("date", "amount", "currency") .match("Buchung auf Kontonummer [\\d ]* mit Wertstellung (?<date>\\d+.\\d+.\\d{4}+) (?<currency>\\w{3}+) (?<amount>[\\d.]+,\\d+)") .assign((t, v) -> { t.setDate(asDate(v.get("date"))); t.setAmount(asAmount(v.get("amount"))); t.setCurrencyCode(v.get("currency")); }) .section("provision", "currency") // .optional() .match("Provision( \\([0-9,]* %\\))? (?<currency>\\w{3}+) (?<provision>[\\d.]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.FEE, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("provision")))))) .section("additional", "currency") // .optional() .match("Weitere Provision der Bank bei der börslichen Orderausführung (?<currency>\\w{3}+) (?<additional>[\\d.]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.FEE, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("additional")))))) .section("xetra", "currency") // .optional() // .match("XETRA-Kosten (?<currency>\\w{3}+) (?<xetra>[\\d.]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.FEE, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("xetra")))))) .wrap(t -> new BuySellEntryItem(t))); } @SuppressWarnings("nls") private void addSellTransaction() { DocumentType type = new DocumentType("Verkauf von Wertpapieren"); this.addDocumentTyp(type); Block block = new Block("Abrechnung: Verkauf von Wertpapieren"); type.addBlock(block); block.set(new Transaction<BuySellEntry>() .subject(() -> { BuySellEntry entry = new BuySellEntry(); entry.setType(PortfolioTransaction.Type.SELL); return entry; }) .section("wkn", "isin", "name", "currency") .find("Filialnummer Depotnummer Wertpapierbezeichnung Seite") // .match("^.{15}(?<name>.*)$") // .match("^WKN (?<wkn>[^ ]*) (.*)$") // .match("^ISIN (?<isin>[^ ]*) Kurs (?<currency>\\w{3}+) (.*)$") // .assign((t, v) -> t.setSecurity(getOrCreateSecurity(v))) .section("shares") // .match("^WKN [^ ]* Nominal ST (?<shares>\\d+(,\\d+)?)") .assign((t, v) -> t.setShares(asShares(v.get("shares")))) .section("date", "amount", "currency") .match("Buchung auf Kontonummer [\\d ]* mit Wertstellung (?<date>\\d+.\\d+.\\d{4}+) (?<currency>\\w{3}+) (?<amount>[\\d.]+,\\d+)") .assign((t, v) -> { t.setDate(asDate(v.get("date"))); t.setAmount(asAmount(v.get("amount"))); t.setCurrencyCode(asCurrencyCode(v.get("currency"))); }) .section("tax", "currency") // .optional() // .match("Kapitalertragsteuer (?<currency>\\w{3}+) (?<tax>[\\d.-]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.TAX, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("tax")))))) .section("soli", "currency") // .optional() .match("Solidaritätszuschlag auf Kapitalertragsteuer (?<currency>\\w{3}+) (?<soli>[\\d.-]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.TAX, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("soli")))))) .section("provision", "currency") // .optional().match("Provision.*(?<currency>\\w{3}+) -(?<provision>[\\d.]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.FEE, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("provision")))))) .section("charges", "currency") // .optional().match("Fremde Spesen und Auslagen (?<currency>\\w{3}+) -(?<charges>[\\d.]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.FEE, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("charges")))))) .section("additional", "currency") // .optional() .match("Weitere Provision der Bank bei der börslichen Orderausf.*hrung (?<currency>\\w{3}+) -(?<additional>[\\d.]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.FEE, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("additional")))))) .section("xetra", "currency") // .optional() // .match("XETRA-Kosten (?<currency>\\w{3}+) -(?<xetra>[\\d.]+,\\d+)") .assign((t, v) -> t.getPortfolioTransaction().addUnit(new Unit(Unit.Type.FEE, // Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("xetra")))))) .wrap(t -> new BuySellEntryItem(t))); } @SuppressWarnings("nls") private void addDividendTransaction(String nameOfTransaction) { DocumentType type = new DocumentType(nameOfTransaction); this.addDocumentTyp(type); Block block = new Block(nameOfTransaction); type.addBlock(block); block.set(new Transaction<AccountTransaction>() .subject(() -> { AccountTransaction transaction = new AccountTransaction(); transaction.setType(AccountTransaction.Type.DIVIDENDS); return transaction; }) .section("wkn", "isin", "name", "currency") // .find("Stück WKN ISIN") // .match("(\\d+,\\d*) (?<wkn>\\S*) (?<isin>\\S*)") // .match("^(?<name>.*)$") // .match("Bruttoertrag ([\\d.]+,\\d+) (?<currency>\\w{3}+).*") // .assign((t, v) -> t.setSecurity(getOrCreateSecurity(v))) .section("shares") // .match("(?<shares>\\d+,\\d*) (\\S*) (\\S*)") .assign((t, v) -> t.setShares(asShares(v.get("shares")))) .section("date", "amount", "currency") .match("Gutschrift mit Wert (?<date>\\d+.\\d+.\\d{4}+) (?<amount>[\\d.]+,\\d+) (?<currency>\\w{3}+)") .assign((t, v) -> { t.setDate(asDate(v.get("date"))); t.setAmount(asAmount(v.get("amount"))); t.setCurrencyCode(asCurrencyCode(v.get("currency"))); }) .section("grossValue", "currency") // .optional() // .match("Bruttoertrag (?<grossValue>[\\d.]+,\\d+) (?<currency>\\w{3}+)").assign((t, v) -> { Money grossValue = Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("grossValue"))); // calculating taxes as the difference between gross // value and transaction amount Money taxes = MutableMoney.of(t.getCurrencyCode()).add(grossValue) .subtract(t.getMonetaryAmount()).toMoney(); if (!taxes.isZero()) t.addUnit(new Unit(Unit.Type.TAX, taxes)); }) // will match gross value only if forex data exists .section("forexSum", "forexCurrency", "grossValue", "currency", "exchangeRate") // .optional() // .match("Bruttoertrag (?<forexSum>[\\d.]+,\\d+) (?<forexCurrency>\\w{3}+) (?<grossValue>[\\d.]+,\\d+) (?<currency>\\w{3}+)") .match("Umrechnungskurs (\\w{3}+) zu (\\w{3}+) (?<exchangeRate>[\\d.]+,\\d+)") // .assign((t, v) -> { Money grossValue = Money.of(asCurrencyCode(v.get("currency")), asAmount(v.get("grossValue"))); Money forex = Money.of(asCurrencyCode(v.get("forexCurrency")), asAmount(v.get("forexSum"))); BigDecimal exchangeRate = BigDecimal.ONE.divide( // asExchangeRate(v.get("exchangeRate")), 10, BigDecimal.ROUND_HALF_DOWN); Unit unit = new Unit(Unit.Type.GROSS_VALUE, grossValue, forex, exchangeRate); // add gross value unit only if currency code of // security actually matches if (unit.getForex().getCurrencyCode().equals(t.getSecurity().getCurrencyCode())) t.addUnit(unit); // calculating taxes as the difference between gross // value and transaction amount Money taxes = MutableMoney.of(t.getCurrencyCode()).add(grossValue) .subtract(t.getMonetaryAmount()).toMoney(); if (!taxes.isZero()) t.addUnit(new Unit(Unit.Type.TAX, taxes)); }) .wrap(t -> new TransactionItem(t))); } @Override public String getLabel() { return Messages.PDFdbLabel; } }