package name.abuchen.portfolio.model; import java.io.Serializable; import java.time.LocalDate; import java.util.Comparator; import java.util.ResourceBundle; import name.abuchen.portfolio.money.Money; import name.abuchen.portfolio.money.MoneyCollectors; public class AccountTransaction extends Transaction { public enum Type { DEPOSIT(false), REMOVAL(true), // INTEREST(false), INTEREST_CHARGE(true), // DIVIDENDS(false), // FEES(true), FEES_REFUND(false), // TAXES(true), TAX_REFUND(false), // BUY(true), SELL(false), // TRANSFER_IN(false), TRANSFER_OUT(true); private static final ResourceBundle RESOURCES = ResourceBundle.getBundle("name.abuchen.portfolio.model.labels"); //$NON-NLS-1$ private final boolean isDebit; private Type(boolean isDebit) { this.isDebit = isDebit; } public boolean isDebit() { return isDebit; } public boolean isCredit() { return !isDebit; } @Override public String toString() { return RESOURCES.getString("account." + name()); //$NON-NLS-1$ } } /** * Comparator to sort by date, amount, type, and hash code in order to have * a stable enough sort order to calculate the balance per transaction. */ public static final class ByDateAmountTypeAndHashCode implements Comparator<AccountTransaction>, Serializable { private static final long serialVersionUID = 1L; @Override public int compare(AccountTransaction t1, AccountTransaction t2) { int compare = t1.getDate().compareTo(t2.getDate()); if (compare != 0) return compare; compare = Long.compare(t1.getAmount(), t2.getAmount()); if (compare != 0) return compare; compare = t1.getType().compareTo(t2.getType()); if (compare != 0) return compare; return Integer.compare(t1.hashCode(), t2.hashCode()); } } private Type type; public AccountTransaction() { // needed for xstream de-serialization } public AccountTransaction(LocalDate date, String currencyCode, long amount, Security security, Type type) { super(date, currencyCode, amount, security, 0, null); this.type = type; } public Type getType() { return type; } public void setType(Type type) { this.type = type; } /** * Returns the gross value, i.e. the value including taxes. See * {@link #getGrossValue()}. */ public long getGrossValueAmount() { // at the moment, only dividend transaction support taxes if (!(this.type == Type.DIVIDENDS || this.type == Type.INTEREST)) throw new UnsupportedOperationException(); long taxes = getUnits().filter(u -> u.getType() == Unit.Type.TAX) .collect(MoneyCollectors.sum(getCurrencyCode(), u -> u.getAmount())).getAmount(); return getAmount() + taxes; } /** * Returns the gross value, i.e. the value before taxes are applied. At the * moment, only dividend transactions are supported. */ public Money getGrossValue() { return Money.of(getCurrencyCode(), getGrossValueAmount()); } }