diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/csv/CSVAccountTransactionExtractorTest.java b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/csv/CSVAccountTransactionExtractorTest.java index a4732d333f..dfa7c06168 100644 --- a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/csv/CSVAccountTransactionExtractorTest.java +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/csv/CSVAccountTransactionExtractorTest.java @@ -23,6 +23,7 @@ import name.abuchen.portfolio.model.BuySellEntry; import name.abuchen.portfolio.model.Client; import name.abuchen.portfolio.model.Security; +import name.abuchen.portfolio.model.Transaction.Unit; import name.abuchen.portfolio.money.CurrencyUnit; import name.abuchen.portfolio.money.Money; import name.abuchen.portfolio.money.Values; @@ -345,4 +346,28 @@ public void testRequiredFieldAmount() assertThat(results, empty()); assertThat(errors.size(), is(1)); } + + @Test + public void testTaxesOnDividends() + { + Client client = new Client(); + + CSVExtractor extractor = new CSVAccountTransactionExtractor(client); + + List errors = new ArrayList(); + List results = extractor.extract(0, + Arrays.asList( // + new String[] { "2013-01-01", "DE0007164600", "SAP.DE", "", "100", "EUR", + "DIVIDENDS", "SAP SE", "10", "Notiz", "10" }), + buildField2Column(extractor), errors); + + assertThat(results.size(), is(2)); + new AssertImportActions().check(results, CurrencyUnit.EUR); + + AccountTransaction t = (AccountTransaction) results.stream().filter(i -> i instanceof TransactionItem).findAny() + .get().getSubject(); + assertThat(t.getType(), is(AccountTransaction.Type.DIVIDENDS)); + assertThat(t.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, 100_00))); + assertThat(t.getUnitSum(Unit.Type.TAX), is(Money.of(CurrencyUnit.EUR, 10_00))); + } } diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/actions/CheckCurrenciesAction.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/actions/CheckCurrenciesAction.java index 0982bfc604..2e885b68ac 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/actions/CheckCurrenciesAction.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/actions/CheckCurrenciesAction.java @@ -62,6 +62,22 @@ public Status process(AccountTransaction transaction, Account account) Status status = checkGrossValueAndUnitsAgainstSecurity(transaction); if (status.getCode() != Status.Code.OK) return status; + + if (transaction.getType() == AccountTransaction.Type.DIVIDENDS) + { + // tax must be < than transaction amount + Money taxes = transaction.getUnits() // + .filter(u -> u.getType() == Unit.Type.TAX) // + .map(u -> u.getAmount()) // + .collect(MoneyCollectors.sum(transaction.getCurrencyCode())); + + if (!transaction.getMonetaryAmount().isGreaterOrEqualThan(taxes)) + return new Status(Status.Code.ERROR, + MessageFormat.format(Messages.MsgCheckTaxAndFeesTooHigh, + Values.Money.format(transaction.getMonetaryAmount()), + Values.Money.format(taxes))); + } + } } diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/csv/CSVAccountTransactionExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/csv/CSVAccountTransactionExtractor.java index 7d2cde7f6b..91078e4836 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/csv/CSVAccountTransactionExtractor.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/csv/CSVAccountTransactionExtractor.java @@ -20,6 +20,7 @@ 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.money.Money; /* package */ class CSVAccountTransactionExtractor extends BaseCSVExtractor @@ -39,15 +40,15 @@ fields.add(new Field(Messages.CSVColumn_SecurityName).setOptional(true)); fields.add(new AmountField(Messages.CSVColumn_Shares).setOptional(true)); fields.add(new Field(Messages.CSVColumn_Note).setOptional(true)); + fields.add(new AmountField(Messages.CSVColumn_Taxes).setOptional(true)); } @Override void extract(List items, String[] rawValues, Map field2column) throws ParseException { // check if we have a security - Security security = getSecurity(rawValues, field2column, s -> { - s.setCurrencyCode(getCurrencyCode(Messages.CSVColumn_TransactionCurrency, rawValues, field2column)); - }); + Security security = getSecurity(rawValues, field2column, s -> s.setCurrencyCode( + getCurrencyCode(Messages.CSVColumn_TransactionCurrency, rawValues, field2column))); // check for the transaction amount Money amount = getMoney(rawValues, field2column); @@ -61,6 +62,7 @@ void extract(List items, String[] rawValues, Map field2col throw new ParseException(MessageFormat.format(Messages.CSVImportMissingField, Messages.CSVColumn_Date), 0); String note = getText(Messages.CSVColumn_Note, rawValues, field2column); Long shares = getShares(Messages.CSVColumn_Shares, rawValues, field2column); + Long taxes = getAmount(Messages.CSVColumn_Taxes, rawValues, field2column); switch (type) { @@ -118,6 +120,8 @@ void extract(List items, String[] rawValues, Map field2col t.setNote(note); if (shares != null && type == Type.DIVIDENDS) t.setShares(Math.abs(shares)); + if (type == Type.DIVIDENDS && taxes != null && taxes.longValue() != 0) + t.addUnit(new Unit(Unit.Type.TAX, Money.of(t.getCurrencyCode(), Math.abs(taxes)))); items.add(new TransactionItem(t)); break; default: diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/csv/CSVExporter.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/csv/CSVExporter.java index 66db378304..68725db8a1 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/csv/CSVExporter.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/csv/CSVExporter.java @@ -44,6 +44,7 @@ public void exportAccountTransactions(File file, Account account) throws IOExcep Messages.CSVColumn_Type, // Messages.CSVColumn_Value, // Messages.CSVColumn_TransactionCurrency, // + Messages.CSVColumn_Taxes, // Messages.CSVColumn_Shares, // Messages.CSVColumn_ISIN, // Messages.CSVColumn_WKN, // @@ -57,6 +58,8 @@ public void exportAccountTransactions(File file, Account account) throws IOExcep printer.print(t.getType().toString()); printer.print(Values.Amount.format(t.getType().isDebit() ? -t.getAmount() : t.getAmount())); printer.print(t.getCurrencyCode()); + printer.print(t.getType() == AccountTransaction.Type.DIVIDENDS + ? Values.Amount.format(t.getUnitSum(Unit.Type.TAX).getAmount()) : ""); //$NON-NLS-1$ printer.print(t.getShares() != 0 ? Values.Share.format(t.getShares()) : ""); //$NON-NLS-1$ printSecurityInfo(printer, t);