package name.abuchen.portfolio.datatransfer.pdf; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.collection.IsEmptyCollection.empty; import static org.junit.Assert.assertThat; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.Scanner; import org.junit.Test; import name.abuchen.portfolio.datatransfer.Extractor.BuySellEntryItem; import name.abuchen.portfolio.datatransfer.Extractor.Item; import name.abuchen.portfolio.datatransfer.Extractor.SecurityItem; import name.abuchen.portfolio.datatransfer.Extractor.TransactionItem; import name.abuchen.portfolio.datatransfer.ImportAction.Status; import name.abuchen.portfolio.datatransfer.ImportAction.Status.Code; import name.abuchen.portfolio.datatransfer.actions.AssertImportActions; import name.abuchen.portfolio.datatransfer.actions.CheckCurrenciesAction; import name.abuchen.portfolio.model.Account; 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.Unit; import name.abuchen.portfolio.model.Transaction.Unit.Type; import name.abuchen.portfolio.money.CurrencyUnit; import name.abuchen.portfolio.money.Money; import name.abuchen.portfolio.money.Quote; import name.abuchen.portfolio.money.Values; @SuppressWarnings("nls") public class ConsorsbankPDFExtractorTest { private Security assertSecurity(List<Item> results, boolean mustHaveIsin) { Optional<Item> item = results.stream().filter(i -> i instanceof SecurityItem).findFirst(); assertThat(item.isPresent(), is(true)); Security security = ((SecurityItem) item.get()).getSecurity(); if (mustHaveIsin) assertThat(security.getIsin(), is("LU0392494562")); assertThat(security.getWkn(), is("ETF110")); assertThat(security.getName(), is("COMS.-MSCI WORL.T.U.ETF I")); assertThat(security.getCurrencyCode(), is(CurrencyUnit.EUR)); return security; } @Test public void testErtragsgutschrift() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankErtragsgutschrift.txt")), errors); assertThat(errors, empty()); assertThat(results.size(), is(2)); new AssertImportActions().check(results, CurrencyUnit.EUR); // check security Security security = assertSecurity(results, false); // check transaction Optional<Item> item = results.stream().filter(i -> i instanceof TransactionItem).findFirst(); assertDividendTransaction(security, item); // check tax AccountTransaction t = (AccountTransaction) item.get().getSubject(); assertThat(t.getUnitSum(Type.TAX), is(Money.of("EUR", 111_00L + 6_10L))); } private void assertDividendTransaction(Security security, Optional<Item> item) { 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-05-08"))); assertThat(transaction.getMonetaryAmount(), is(Money.of("EUR", 326_90L))); assertThat(transaction.getShares(), is(Values.Share.factorize(1370))); } @Test public void testErtragsgutschrift2() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankErtragsgutschrift2.txt")), errors); assertThat(errors, empty()); // since taxes are zero, no tax transaction must be created assertThat(results.size(), is(2)); new AssertImportActions().check(results, CurrencyUnit.EUR); Optional<Item> item = results.stream().filter(i -> i instanceof TransactionItem).findFirst(); assertThat(item.isPresent(), is(true)); assertThat(item.get().getAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1444)))); } @Test public void testErtragsgutschrift3() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankErtragsgutschrift3.txt")), errors); assertThat(errors, empty()); // since taxes are zero, no tax transaction must be created assertThat(results.size(), is(2)); // check security Security security = results.stream().filter(i -> i instanceof SecurityItem).findAny().get().getSecurity(); assertThat(security.getWkn(), is("850866")); assertThat(security.getName(), is("DEERE & CO.")); // check dividend transaction AccountTransaction t = (AccountTransaction) results.stream().filter(i -> i instanceof TransactionItem).filter( i -> ((AccountTransaction) i.getSubject()).getType() == AccountTransaction.Type.DIVIDENDS) .findAny().get().getSubject(); assertThat(t.getDate(), is(LocalDate.parse("2015-11-02"))); assertThat(t.getShares(), is(Values.Share.factorize(300))); assertThat(t.getMonetaryAmount(), is(Money.of("EUR", 121_36))); assertThat(t.getUnit(Unit.Type.GROSS_VALUE).get().getForex(), is(Money.of("USD", 180_00))); // check tax assertThat(t.getUnitSum(Type.TAX), is(Money.of("EUR", 16_30 + 89 + 24_45))); } @Test public void testErtragsgutschrift4() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankErtragsgutschrift4.txt")), errors); assertThat(errors, empty()); // since taxes are zero, no tax transaction must be created assertThat(results.size(), is(2)); // check security Security security = results.stream().filter(i -> i instanceof SecurityItem).findFirst().get().getSecurity(); assertThat(security.getWkn(), is("854242")); assertThat(security.getName(), is("WESTPAC BANKING CORP.")); // 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("2015-07-02"))); assertThat(t.getShares(), is(Values.Share.factorize(1.0002))); assertThat(t.getMonetaryAmount(), is(Money.of("EUR", 46))); assertThat(t.getUnit(Unit.Type.GROSS_VALUE).get().getForex(), is(Money.of("AUD", 93))); // check tax assertThat(t.getUnitSum(Type.TAX), is(Money.of("EUR", 16))); } @Test public void testErtragsgutschrift5() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankErtragsgutschrift5.txt")), 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("885823")); assertThat(security.getName(), is("GILEAD SCIENCES 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("2015-06-29"))); assertThat(t.getShares(), is(Values.Share.factorize(0.27072))); assertThat(t.getMonetaryAmount(), is(Money.of("EUR", 8))); assertThat(t.getUnit(Unit.Type.GROSS_VALUE).get().getForex(), is(Money.of("USD", 12))); // check tax assertThat(t.getUnitSum(Type.TAX), is(Money.of("EUR", 1 + 2))); } @Test public void testErtragsgutschrift8() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankErtragsgutschrift8.txt")), 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("891106")); assertThat(security.getName(), is("ROCHE HOLDING AG")); // 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("2014-04-22"))); assertThat(t.getShares(), is(Values.Share.factorize(80))); assertThat(t.getMonetaryAmount(), is(Money.of("EUR", 33_51))); assertThat(t.getGrossValue(), is(Money.of("EUR", 64_08))); // check tax assertThat(t.getUnitSum(Type.TAX), is(Money.of("EUR", 30_57))); checkCurrency(CurrencyUnit.EUR, t); } @Test public void testErtragsgutschrift9() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankErtragsgutschrift9.txt")), 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("A1409D")); assertThat(security.getName(), is("Welltower 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-05-20"))); assertThat(t.getShares(), is(Values.Share.factorize(50))); assertThat(t.getMonetaryAmount(), is(Money.of("EUR", 32_51))); assertThat(t.getGrossValue(), is(Money.of("EUR", 38_25))); // check tax assertThat(t.getUnitSum(Type.TAX), is(Money.of("EUR", 5_74))); checkCurrency(CurrencyUnit.EUR, t); } @Test public void testErtragsgutschrift8WithExistingSecurity() throws IOException { Client client = new Client(); ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(client) { @Override protected String strip(File file) throws IOException { return from(file.getName()); } }; Security existingSecurity = new Security("ROCHE HOLDING AG", CurrencyUnit.EUR); existingSecurity.setWkn("891106"); client.addSecurity(existingSecurity); List<Exception> errors = new ArrayList<Exception>(); List<Item> results = extractor.extract(Arrays.asList(new File("ConsorsbankErtragsgutschrift8.txt")), errors); assertThat(errors, empty()); assertThat(results.size(), is(1)); // 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.getSecurity(), is(existingSecurity)); assertThat(t.getDate(), is(LocalDate.parse("2014-04-22"))); assertThat(t.getShares(), is(Values.Share.factorize(80))); assertThat(t.getMonetaryAmount(), is(Money.of("EUR", 33_51))); assertThat(t.getGrossValue(), is(Money.of("EUR", 64_08))); // check tax assertThat(t.getUnitSum(Type.TAX), is(Money.of("EUR", 30_57))); checkCurrency(CurrencyUnit.EUR, t); } @Test public void testBezug1() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankBezug1.txt")), 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.getIsin(), is("DE000A0V9L94")); assertThat(security.getWkn(), is("A0V9L9")); assertThat(security.getName(), is("EYEMAXX R.EST.AG")); assertThat(security.getCurrencyCode(), is(CurrencyUnit.EUR)); // check buy sell transaction Optional<Item> item = results.stream().filter(i -> i instanceof BuySellEntryItem).findFirst(); assertThat(item.isPresent(), is(true)); assertThat(item.get().getSubject(), instanceOf(BuySellEntry.class)); BuySellEntry entry = (BuySellEntry) item.get().getSubject(); assertThat(entry.getPortfolioTransaction().getType(), is(PortfolioTransaction.Type.BUY)); assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.BUY)); assertThat(entry.getPortfolioTransaction().getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 399_96L))); assertThat(entry.getPortfolioTransaction().getDate(), is(LocalDate.parse("2016-05-10"))); assertThat(entry.getPortfolioTransaction().getShares(), is(66_000000L)); assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.FEE), is(Money.of(CurrencyUnit.EUR, 3_96L))); } @Test public void testWertpapierVerkauf1() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankVerkauf1.txt")), 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("A0DPR2")); assertThat(security.getName(), is("VOLKSWAGEN AG VZ ADR1/5")); new AssertImportActions().check(results, CurrencyUnit.EUR); // check buy sell transaction Item item = results.get(0); BuySellEntry entry = (BuySellEntry) item.getSubject(); PortfolioTransaction t = entry.getPortfolioTransaction(); assertThat(t.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 5794_56L))); assertThat(t.getUnitSum(Type.FEE), is(Money.of(CurrencyUnit.EUR, 26_65L))); assertThat(t.getUnitSum(Type.TAX), is(Money.of(CurrencyUnit.EUR, 226_79L))); assertThat(t.getDate(), is(LocalDate.parse("2015-02-20"))); assertThat(t.getShares(), is(Values.Share.factorize(140))); assertThat(t.getGrossPricePerShare(), is(Quote.of(CurrencyUnit.EUR, Values.Quote.factorize(43.2)))); } @Test public void testWertpapierKauf() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankKauf.txt")), errors); assertThat(errors, empty()); assertThat(results.size(), is(2)); new AssertImportActions().check(results, CurrencyUnit.EUR); // check security assertSecurity(results, true); // check buy sell transaction Optional<Item> item = results.stream().filter(i -> i instanceof BuySellEntryItem).findFirst(); assertThat(item.isPresent(), is(true)); assertThat(item.get().getSubject(), instanceOf(BuySellEntry.class)); BuySellEntry entry = (BuySellEntry) item.get().getSubject(); assertThat(entry.getPortfolioTransaction().getType(), is(PortfolioTransaction.Type.BUY)); assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.BUY)); assertThat(entry.getPortfolioTransaction().getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 5000_00L))); assertThat(entry.getPortfolioTransaction().getDate(), is(LocalDate.parse("2015-01-15"))); assertThat(entry.getPortfolioTransaction().getShares(), is(132_802120L)); assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.FEE), is(Money.of(CurrencyUnit.EUR, 0L))); } @Test public void testWertpapierKauf2() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankKauf2.txt")), errors); assertThat(errors, empty()); assertThat(results.size(), is(2)); new AssertImportActions().check(results, CurrencyUnit.EUR); // check security Optional<Item> secItem = results.stream().filter(i -> i instanceof SecurityItem).findFirst(); assertThat(secItem.isPresent(), is(true)); Security security = ((SecurityItem) secItem.get()).getSecurity(); assertThat(security.getIsin(), is("DE000A0L1NN5")); assertThat(security.getWkn(), is("A0L1NN")); assertThat(security.getName(), is("HELIAD EQ.PARTN.KGAA")); assertThat(security.getCurrencyCode(), is(CurrencyUnit.EUR)); // check buy sell transaction Optional<Item> item = results.stream().filter(i -> i instanceof BuySellEntryItem).findFirst(); assertThat(item.isPresent(), is(true)); assertThat(item.get().getSubject(), instanceOf(BuySellEntry.class)); BuySellEntry entry = (BuySellEntry) item.get().getSubject(); assertThat(entry.getPortfolioTransaction().getType(), is(PortfolioTransaction.Type.BUY)); assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.BUY)); assertThat(entry.getPortfolioTransaction().getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 1387_85L))); assertThat(entry.getPortfolioTransaction().getDate(), is(LocalDate.parse("2015-09-21"))); assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(250))); assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.FEE), is(Money.of(CurrencyUnit.EUR, 17_85L))); assertThat(entry.getPortfolioTransaction().getGrossPricePerShare(), is(Quote.of(CurrencyUnit.EUR, Values.Quote.factorize(5.48)))); } @Test public void testWertpapierKaufSparplan() throws IOException { ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(new Client()) { @Override protected 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("ConsorsbankKaufSparplan.txt")), errors); assertThat(errors, empty()); assertThat(results.size(), is(2)); new AssertImportActions().check(results, CurrencyUnit.EUR); // check security Optional<Item> secItem = results.stream().filter(i -> i instanceof SecurityItem).findFirst(); assertThat(secItem.isPresent(), is(true)); Security security = ((SecurityItem) secItem.get()).getSecurity(); assertThat(security.getIsin(), is("PO6527623674")); assertThat(security.getWkn(), is("SP110Y")); assertThat(security.getName(), is("Sparplanname")); assertThat(security.getCurrencyCode(), is(CurrencyUnit.EUR)); // check buy sell transaction Optional<Item> item = results.stream().filter(i -> i instanceof BuySellEntryItem).findFirst(); assertThat(item.isPresent(), is(true)); assertThat(item.get().getSubject(), instanceOf(BuySellEntry.class)); BuySellEntry entry = (BuySellEntry) item.get().getSubject(); assertThat(entry.getPortfolioTransaction().getType(), is(PortfolioTransaction.Type.BUY)); assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.BUY)); assertThat(entry.getPortfolioTransaction().getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 100_00L))); assertThat(entry.getPortfolioTransaction().getDate(), is(LocalDate.parse("2016-06-15"))); assertThat(entry.getPortfolioTransaction().getShares(), is(Values.Share.factorize(6.43915))); assertThat(entry.getPortfolioTransaction().getUnitSum(Unit.Type.FEE), is(Money.of(CurrencyUnit.EUR, 0_00L))); assertThat(entry.getPortfolioTransaction().getGrossPricePerShare(), is(Quote.of(CurrencyUnit.EUR, Values.Quote.factorize(15.53)))); } @Test public void testWertpapierKaufIfSecurityIsPresent() throws IOException { Client client = new Client(); Security s = new Security(); s.setName("COMS.-MSCI WORL.T.U.ETF I"); s.setWkn("ETF110"); client.addSecurity(s); ConsorsbankPDFExctractor extractor = new ConsorsbankPDFExctractor(client) { @Override protected 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("ConsorsbankKauf.txt")), errors); assertThat(errors, empty()); assertThat(results.size(), is(1)); new AssertImportActions().check(results, CurrencyUnit.EUR); // check buy sell transaction Item item = results.get(0); BuySellEntry entry = (BuySellEntry) item.getSubject(); assertThat(entry.getPortfolioTransaction().getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 5000_00L))); } private String from(String resource) { try (Scanner scanner = new Scanner(getClass().getResourceAsStream(resource), StandardCharsets.UTF_8.name())) { return scanner.useDelimiter("\\A").next(); } } private void checkCurrency(final String accountCurrency, AccountTransaction transaction) { Account account = new Account(); account.setCurrencyCode(accountCurrency); Status status = new CheckCurrenciesAction().process(transaction, account); assertThat(status.getCode(), is(Code.OK)); } }