@Test public void testErtragsgutschriftWhenSecurityExists() throws IOException { Client client = new Client(); Security security = new Security("BASF", "DE000BASF111", null, null); client.addSecurity(security); DeutscheBankPDFExctractor extractor = new DeutscheBankPDFExctractor(client) { @Override String strip(File file) throws IOException { return from("DeutscheBankErtragsgutschrift.txt"); } }; List<Exception> errors = new ArrayList<Exception>(); List<Item> results = extractor.extract(Arrays.asList(new File("t")), errors); assertThat(errors, empty()); assertThat(results.size(), is(1)); new AssertImportActions().check(results, CurrencyUnit.EUR); // check transaction AccountTransaction transaction = (AccountTransaction) results.get(0).getSubject(); assertThat(transaction.getType(), is(AccountTransaction.Type.DIVIDENDS)); assertThat(transaction.getSecurity(), is(security)); }
private static void collectAccountTransactions( Client client, Date start, Date end, List<Transaction> transactions) { for (Account account : client.getAccounts()) { for (AccountTransaction t : account.getTransactions()) { if (t.getDate().getTime() > start.getTime() && t.getDate().getTime() <= end.getTime()) { switch (t.getType()) { case DEPOSIT: case REMOVAL: case TRANSFER_IN: case TRANSFER_OUT: transactions.add(t); break; case BUY: case SELL: case FEES: case TAXES: case DIVIDENDS: case INTEREST: case TAX_REFUND: break; default: throw new UnsupportedOperationException(); } } } } }
@Override public Status process(AccountTransaction transaction, Account account) { // ensure consistency (in case the user deleted the creation of the // security via the dialog) if (transaction.getSecurity() != null) process(transaction.getSecurity()); account.addTransaction(transaction); return Status.OK_STATUS; }
private void addBackOfProfitsTransaction() { DocumentType type = new DocumentType("Ertragsthesaurierung"); this.addDocumentTyp(type); Block block = new Block("Ertragsthesaurierung(.*)"); type.addBlock(block); Transaction<AccountTransaction> pdfTransaction = new Transaction<AccountTransaction>(); pdfTransaction.subject( () -> { AccountTransaction transaction = new AccountTransaction(); transaction.setType(AccountTransaction.Type.DIVIDENDS); return transaction; }); block.set(pdfTransaction); pdfTransaction .section("name", "isin") // .find("Gattungsbezeichnung(.*) ISIN") // Commerzbank AG Inhaber-Aktien o.N. DE000CBK1001 // 5,5% TUI AG Wandelanl.v.2009(2014) 17.11.2014 // 17.11.2010 DE000TUAG117 .match("(?<name>.*?) (\\d+.\\d+.\\d{4} ){0,2}(?<isin>[^ ]\\S*)$") // .assign( (t, v) -> { t.setSecurity(getOrCreateSecurity(v)); }) .section("notation", "shares", "date") .find("Nominal (Ex-Tag )?Zahltag (.*etrag pro .*)?(Zinssatz.*)?") // STK 28,000 02.03.2015 04.03.2015 EUR 0,088340 .match( "(?<notation>^\\w{3}+) (?<shares>\\d{1,3}(\\.\\d{3})*(,\\d{3})?) (\\d+.\\d+.\\d{4}+) (?<date>\\d+.\\d+.\\d{4}+)(.*)") .assign( (t, v) -> { String notation = v.get("notation"); if (notation != null && !notation.equalsIgnoreCase("STK")) { // Prozent-Notierung, Workaround.. t.setShares((asShares(v.get("shares")) / 100)); } else { t.setShares(asShares(v.get("shares"))); } t.setDate(asDate(v.get("date"))); }) .section("amount", "currency") .match( "Steuerpflichtiger Betrag (.*) (?<currency>\\w{3}+) (?<amount>\\d{1,3}(\\.\\d{3})*(,\\d{2})?)") .assign( (t, v) -> { t.setAmount(asAmount(v.get("amount"))); t.setCurrencyCode(asCurrencyCode(v.get("currency"))); }) .wrap(t -> new TransactionItem(t)); addTaxesSectionsAccount(pdfTransaction); }
@Test public void testErtragsgutschrift() throws IOException { DeutscheBankPDFExctractor extractor = new DeutscheBankPDFExctractor(new Client()) { @Override String strip(File file) throws IOException { return from("DeutscheBankErtragsgutschrift.txt"); } }; List<Exception> errors = new ArrayList<Exception>(); List<Item> results = extractor.extract(Arrays.asList(new File("t")), errors); assertThat(errors, empty()); assertThat(results.size(), is(2)); new AssertImportActions().check(results, CurrencyUnit.EUR); // check security Security security = assertSecurity(results); // check transaction Optional<Item> item = results.stream().filter(i -> i instanceof TransactionItem).findFirst(); assertThat(item.isPresent(), is(true)); assertThat(item.get().getSubject(), instanceOf(AccountTransaction.class)); AccountTransaction transaction = (AccountTransaction) item.get().getSubject(); assertThat(transaction.getType(), is(AccountTransaction.Type.DIVIDENDS)); assertThat(transaction.getSecurity(), is(security)); assertThat(transaction.getDate(), is(LocalDate.parse("2014-12-15"))); assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 1495L))); assertThat(transaction.getShares(), is(Values.Share.factorize(123))); }
private static void collectDatesAndValues( Date start, Date end, ClientSnapshot snapshotStart, ClientSnapshot snapshotEnd, List<Transaction> transactions, List<Date> dates, List<Double> values) { Calendar cal = Calendar.getInstance(); cal.setTime(start); dates.add(cal.getTime()); values.add(-(snapshotStart.getAssets()) / Values.Amount.divider()); for (Transaction t : transactions) { cal.setTime(t.getDate()); dates.add(cal.getTime()); if (t instanceof AccountTransaction) { AccountTransaction at = (AccountTransaction) t; long amount = at.getAmount(); if (at.getType() == Type.DEPOSIT || at.getType() == Type.TRANSFER_IN) amount = -amount; values.add(amount / Values.Amount.divider()); } else if (t instanceof PortfolioTransaction) { PortfolioTransaction pt = (PortfolioTransaction) t; long amount = pt.getAmount(); if (pt.getType() == PortfolioTransaction.Type.DELIVERY_INBOUND || pt.getType() == PortfolioTransaction.Type.TRANSFER_IN) amount = -amount; values.add(amount / Values.Amount.divider()); } else { throw new UnsupportedOperationException(); } } cal.setTime(end); dates.add(cal.getTime()); values.add(snapshotEnd.getAssets() / Values.Amount.divider()); }
private void adaptAccountTransactions( Account account, ReadOnlyAccount pseudoAccount, Set<Security> usedSecurities) { for (AccountTransaction t : account.getTransactions()) { switch (t.getType()) { case BUY: if (portfolios.contains(t.getCrossEntry().getCrossOwner(t))) pseudoAccount.internalAddTransaction(t); else pseudoAccount.internalAddTransaction(convertTo(t, AccountTransaction.Type.REMOVAL)); break; case SELL: if (portfolios.contains(t.getCrossEntry().getCrossOwner(t))) pseudoAccount.internalAddTransaction(t); else pseudoAccount.internalAddTransaction(convertTo(t, AccountTransaction.Type.DEPOSIT)); break; case TRANSFER_IN: if (accounts.contains(t.getCrossEntry().getCrossOwner(t))) pseudoAccount.internalAddTransaction(t); else pseudoAccount.internalAddTransaction(convertTo(t, AccountTransaction.Type.DEPOSIT)); break; case TRANSFER_OUT: if (accounts.contains(t.getCrossEntry().getCrossOwner(t))) pseudoAccount.internalAddTransaction(t); else pseudoAccount.internalAddTransaction(convertTo(t, AccountTransaction.Type.REMOVAL)); break; case DIVIDENDS: case TAX_REFUND: if (t.getSecurity() == null || usedSecurities.contains(t.getSecurity())) pseudoAccount.internalAddTransaction(t); else pseudoAccount.internalAddTransaction(convertTo(t, AccountTransaction.Type.DEPOSIT)); break; case DEPOSIT: case REMOVAL: case INTEREST: case INTEREST_CHARGE: case TAXES: case FEES: pseudoAccount.internalAddTransaction(t); break; default: throw new UnsupportedOperationException(); } } }
@Test public void testErtragsgutschrift2() throws IOException { DeutscheBankPDFExctractor extractor = new DeutscheBankPDFExctractor(new Client()) { @Override String strip(File file) throws IOException { return from(file.getName()); } }; List<Exception> errors = new ArrayList<Exception>(); List<Item> results = extractor.extract(Arrays.asList(new File("DeutscheBankErtragsgutschrift2.txt")), errors); assertThat(errors, empty()); assertThat(results.size(), is(2)); new AssertImportActions().check(results, CurrencyUnit.EUR); // check security Security security = results.stream().filter(i -> i instanceof SecurityItem).findFirst().get().getSecurity(); assertThat(security.getName(), is("ISHS-MSCI N. AMERIC.UCITS ETF BE.SH.(DT.ZT.)")); assertThat(security.getIsin(), is("DE000A0J2060")); assertThat(security.getWkn(), is("A0J206")); assertThat(security.getCurrencyCode(), is("USD")); // check transaction Optional<Item> item = results.stream().filter(i -> i instanceof TransactionItem).findFirst(); assertThat(item.isPresent(), is(true)); assertThat(item.get().getSubject(), instanceOf(AccountTransaction.class)); AccountTransaction transaction = (AccountTransaction) item.get().getSubject(); assertThat(transaction.getType(), is(AccountTransaction.Type.DIVIDENDS)); assertThat(transaction.getSecurity(), is(security)); assertThat(transaction.getDate(), is(LocalDate.parse("2015-03-24"))); assertThat(transaction.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 16_17L))); assertThat(transaction.getShares(), is(Values.Share.factorize(123))); Optional<Unit> grossValue = transaction.getUnit(Unit.Type.GROSS_VALUE); assertThat(grossValue.isPresent(), is(true)); assertThat(grossValue.get().getAmount(), is(Money.of("EUR", 16_17L))); assertThat(grossValue.get().getForex(), is(Money.of("USD", 17_38L))); assertThat( grossValue.get().getExchangeRate().doubleValue(), IsCloseTo.closeTo(0.930578, 0.000001)); }
private void collectDividends( Portfolio portfolio, ReadOnlyAccount pseudoAccount, Set<Security> usedSecurities) { if (portfolio.getReferenceAccount() == null) return; for (AccountTransaction t : portfolio.getReferenceAccount().getTransactions()) // NOSONAR { if (t.getSecurity() == null) continue; if (!usedSecurities.contains(t.getSecurity())) continue; switch (t.getType()) { case TAX_REFUND: // security must be non-null -> tax refund is relevant for // performance of security case DIVIDENDS: pseudoAccount.internalAddTransaction(t); pseudoAccount.internalAddTransaction( new AccountTransaction( t.getDate(), t.getCurrencyCode(), t.getAmount(), null, AccountTransaction.Type.REMOVAL)); break; case BUY: case TRANSFER_IN: case SELL: case TRANSFER_OUT: case DEPOSIT: case REMOVAL: case INTEREST: case INTEREST_CHARGE: case TAXES: case FEES: // do nothing break; default: throw new UnsupportedOperationException(); } } }
@Test public void testErtragsgutschrift7_USD_Freibetrag_nicht_ausgeschoepft() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()); List<Exception> errors = new ArrayList<Exception>(); URL url = FileLocator.resolve( getClass() .getResource( "ConsorsbankErtragsgutschrift7_USD_Freibetrag_nicht_ausgeschoepft.pdf")); List<Item> results = extractor.extract(Arrays.asList(new File(url.getPath())), errors); assertThat(errors, empty()); assertThat(results.size(), is(2)); // check security Security security = results.stream().filter(i -> i instanceof SecurityItem).findFirst().get().getSecurity(); assertThat(security.getWkn(), is("200417")); assertThat(security.getName(), is("ALTRIA GROUP INC.")); // check dividend transaction AccountTransaction t = (AccountTransaction) results .stream() .filter(i -> i instanceof TransactionItem) .filter( i -> ((AccountTransaction) i.getSubject()).getType() == AccountTransaction.Type.DIVIDENDS) .findFirst() .get() .getSubject(); assertThat(t.getDate(), is(LocalDate.parse("2016-01-11"))); assertThat(t.getShares(), is(Values.Share.factorize(650))); assertThat(t.getMonetaryAmount(), is(Money.of("EUR", 285_60))); assertThat(t.getUnit(Unit.Type.GROSS_VALUE).get().getForex(), is(Money.of("USD", 367_25))); // check tax assertThat(t.getUnitSum(Type.TAX), is(Money.of("EUR", 50_40))); // QUEST }
private AccountTransaction convertTo(AccountTransaction t, AccountTransaction.Type type) { AccountTransaction clone = new AccountTransaction(); clone.setType(type); clone.setDate(t.getDate()); clone.setCurrencyCode(t.getCurrencyCode()); clone.setSecurity(null); // no security for REMOVAL or DEPOSIT clone.setAmount(t.getAmount()); clone.setShares(t.getShares()); // do *not* copy units as REMOVAL and DEPOSIT have never units return clone; }
private void addDividendTransaction() { DocumentType type = new DocumentType("Erträgnisgutschrift"); this.addDocumentTyp(type); // Erträgnisgutschrift allein ist nicht gut hier, da es schon in der // Kopfzeile steht.. Block block = new Block( "Dividendengutschrift.*|Kupongutschrift.*|Erträgnisgutschrift.*(\\d+.\\d+.\\d{4})"); type.addBlock(block); Transaction<AccountTransaction> pdfTransaction = new Transaction<AccountTransaction>(); pdfTransaction.subject( () -> { AccountTransaction transaction = new AccountTransaction(); transaction.setType(AccountTransaction.Type.DIVIDENDS); return transaction; }); block.set(pdfTransaction); pdfTransaction .section("name", "isin") // .find("Gattungsbezeichnung(.*) ISIN") // Commerzbank AG Inhaber-Aktien o.N. DE000CBK1001 // 5,5% TUI AG Wandelanl.v.2009(2014) 17.11.2014 // 17.11.2010 DE000TUAG117 .match("(?<name>.*?) (\\d+.\\d+.\\d{4} ){0,2}(?<isin>[^ ]\\S*)$") // .assign( (t, v) -> { t.setSecurity(getOrCreateSecurity(v)); }) .section("notation", "shares", "date", "amount", "currency") // .find("Nominal (Ex-Tag )?Zahltag (.*etrag pro // .*)?(Zinssatz.*)?") // STK 25,000 17.05.2013 17.05.2013 EUR 0,700000 // Leistungen aus dem steuerlichen Einlagenkonto (§27 // KStG) EUR 17,50 .match( "(?<notation>^\\w{3}+) (?<shares>\\d{1,3}(\\.\\d{3})*(,\\d{3})?) (\\d+.\\d+.\\d{4}+) (?<date>\\d+.\\d+.\\d{4}+)?(.*)") .match( "(?<date>\\d+.\\d+.\\d{4}+)?(\\d{6,12})?(.{7,58} )?(?<currency>\\w{3}+) (?<amount>\\d{1,3}(\\.\\d{3})*(,\\d{2})?)") .assign( (t, v) -> { String notation = v.get("notation"); if (notation != null && !notation.equalsIgnoreCase("STK")) { // Prozent-Notierung, Workaround.. t.setShares((asShares(v.get("shares")) / 100)); } else { t.setShares(asShares(v.get("shares"))); } t.setDate(asDate(v.get("date"))); t.setAmount(asAmount(v.get("amount"))); t.setCurrencyCode(asCurrencyCode(v.get("currency"))); }) .wrap(t -> new TransactionItem(t)); addTaxesSectionsAccount(pdfTransaction); // optional: Reinvestierung in: block = new Block("Reinvestierung.*"); type.addBlock(block); block.set( new Transaction<BuySellEntry>() .subject( () -> { BuySellEntry entry = new BuySellEntry(); entry.setType(PortfolioTransaction.Type.BUY); return entry; }) .section("date") .match( "(^\\w{3}+) (\\d{1,3}(\\.\\d{3})*(,\\d{3})?) (\\d+.\\d+.\\d{4}+) (?<date>\\d+.\\d+.\\d{4}+)?(.*)") .assign((t, v) -> t.setDate(asDate(v.get("date")))) .section("name", "isin") // .find("Die Dividende wurde wie folgt in neue Aktien reinvestiert:") .find("Gattungsbezeichnung ISIN") // .match("(?<name>.*) (?<isin>[^ ]\\S*)$") // .assign( (t, v) -> { t.setSecurity(getOrCreateSecurity(v)); }) .section("notation", "shares", "amount", "currency") // .find("Nominal Reinvestierungspreis") // STK 25,000 EUR 0,700000 .match( "(?<notation>^\\w{3}+) (?<shares>\\d{1,3}(\\.\\d{3})*(,\\d{3})?) (?<currency>\\w{3}+) (?<amount>\\d{1,3}(\\.\\d{3})*(,\\d{2})?)(.*)") .assign( (t, v) -> { String notation = v.get("notation"); if (notation != null && !notation.equalsIgnoreCase("STK")) { // Prozent-Notierung, Workaround.. t.setShares((asShares(v.get("shares")) / 100)); } else { t.setShares(asShares(v.get("shares"))); } t.setCurrencyCode(asCurrencyCode(v.get("currency"))); }) .wrap(t -> new BuySellEntryItem(t))); }
private static void extractSecurityRelatedAccountTransactions( Account account, ReportingPeriod period, Map<Security, SecurityPerformanceRecord> records) { for (AccountTransaction t : account.getTransactions()) { if (t.getSecurity() == null) continue; if (!period.containsTransaction().test(t)) continue; if (t.getType() == AccountTransaction.Type.DIVIDENDS // || t.getType() == AccountTransaction.Type.INTEREST) { DividendTransaction dt = new DividendTransaction(); dt.setDate(t.getDate()); dt.setSecurity(t.getSecurity()); dt.setAccount(account); dt.setCurrencyCode(t.getCurrencyCode()); dt.setAmount(t.getAmount()); dt.setShares(t.getShares()); dt.setNote(t.getNote()); records.get(t.getSecurity()).addTransaction(dt); } else if (t.getType() == AccountTransaction.Type.TAX_REFUND) { records.get(t.getSecurity()).addTransaction(t); } } }