Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds the option for non cash-effective dividend payments #3610

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,10 @@ public class Messages extends NLS
public static String OptionDateIsInTheFuture;
public static String OptionDateIsInThePast;
public static String YearlyPerformanceHeatmapToolTip;
public static String LabelNonCashEffective;
public static String MenuNonCashEffective;
public static String MsgInfoNonCashEffective;
public static String TransactionFilterNonCashEffectiveDividend;
static
{
// initialize resource bundle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
Expand All @@ -46,12 +47,14 @@
import name.abuchen.portfolio.snapshot.ClientSnapshot;
import name.abuchen.portfolio.snapshot.PortfolioSnapshot;
import name.abuchen.portfolio.snapshot.SecurityPosition;
import name.abuchen.portfolio.ui.Images;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.UIConstants;
import name.abuchen.portfolio.ui.dialogs.transactions.AccountTransactionModel.Properties;
import name.abuchen.portfolio.ui.util.FormDataFactory;
import name.abuchen.portfolio.ui.util.LabelOnly;
import name.abuchen.portfolio.ui.util.SWTHelper;
import name.abuchen.portfolio.ui.util.swt.ControlDecoration;

public class AccountTransactionDialog extends AbstractTransactionDialog // NOSONAR
{
Expand Down Expand Up @@ -208,6 +211,25 @@ public void widgetSelected(SelectionEvent e)
total.bindCurrency(Properties.accountCurrencyCode.name());
total.setVisible(model().supportsTaxUnits() || model().supportsFees());

// non cash-effective

Label labelnonCashEffective = new Label(editArea, SWT.LEFT);
labelnonCashEffective.setText(Messages.LabelNonCashEffective);
Button buttonnonCashEffective = new Button(editArea, SWT.CHECK);
IObservableValue<?> targetnonCashEffective = WidgetProperties.buttonSelection().observe(buttonnonCashEffective);
IObservableValue<?> modelnonCashEffective = BeanProperties.value(Properties.nonCashEffective.name())
.observe(model);
context.bindValue(targetnonCashEffective, modelnonCashEffective);
buttonnonCashEffective.setVisible(model().supportsnonCashEffective());
labelnonCashEffective.setVisible(model().supportsnonCashEffective());

Image info = Images.INFO.image();
ControlDecoration deco = new ControlDecoration(buttonnonCashEffective, SWT.CENTER | SWT.LEFT);
deco.setDescriptionText(Messages.MsgInfoNonCashEffective);
deco.setImage(info);
deco.setMarginWidth(2);
deco.show();

// note

Label lblNote = new Label(editArea, SWT.LEFT);
Expand Down Expand Up @@ -244,7 +266,6 @@ public void widgetSelected(SelectionEvent e)
int currencyWidth = currencyWidth(fxGrossAmount.currency);

// date
// shares
forms = forms.thenBelow(dateTime.date.getControl()).label(dateTime.label);

startingWith(dateTime.date.getControl()).thenRight(dateTime.time).thenRight(dateTime.button, 0);
Expand Down Expand Up @@ -294,13 +315,22 @@ public void widgetSelected(SelectionEvent e)
forms = startingWith(taxes.value);
}


// total
if (model().supportsFees() || model().supportsTaxUnits())
{
forms = forms.thenBelow(total.value).width(amountWidth).label(total.label).thenRight(total.currency)
.width(currencyWidth);
}

// cash effectiveness
if (model().supportsnonCashEffective())
{
forms = forms.thenBelow(buttonnonCashEffective).height(SWTHelper.lineHeight(buttonnonCashEffective) * 2)
.left(accounts.value.getControl());
startingWith(buttonnonCashEffective).thenRight(labelnonCashEffective);
}

// note
forms.thenBelow(valueNote).height(SWTHelper.lineHeight(valueNote) * 3).left(accounts.value.getControl())
.right(grossAmount.value).label(lblNote);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public enum Properties
{
security, account, date, time, shares, fxGrossAmount, dividendAmount, exchangeRate, inverseExchangeRate, grossAmount, // NOSONAR
fxTaxes, taxes, fxFees, fees, total, note, exchangeRateCurrencies, inverseExchangeRateCurrencies, // NOSONAR
accountCurrencyCode, securityCurrencyCode, fxCurrencyCode, calculationStatus; // NOSONAR
accountCurrencyCode, securityCurrencyCode, fxCurrencyCode, calculationStatus, nonCashEffective; // NOSONAR
}

public static final Security EMPTY_SECURITY = new Security("-----", ""); //$NON-NLS-1$ //$NON-NLS-2$
Expand Down Expand Up @@ -60,6 +60,7 @@ public enum Properties
private long total;

private String note;
private boolean nonCashEffective;

private IStatus calculationStatus = ValidationStatus.ok();

Expand Down Expand Up @@ -135,6 +136,7 @@ public void applyChanges()
t.setAmount(total);
t.setType(type);
t.setNote(note);
t.setNonCashEffective(nonCashEffective);

t.clearUnits();

Expand Down Expand Up @@ -182,6 +184,7 @@ public void resetToNewTransaction()
setFxTaxes(0);
setNote(null);
setTime(PresetValues.getTime());
setNonCashEffective(false);
}

public boolean supportsShares()
Expand Down Expand Up @@ -228,6 +231,11 @@ public boolean supportsFees()
return type == AccountTransaction.Type.DIVIDENDS;
}

public boolean supportsnonCashEffective()
{
return type == AccountTransaction.Type.DIVIDENDS;
}

public void setSource(Account account, AccountTransaction transaction)
{
this.sourceAccount = account;
Expand Down Expand Up @@ -285,6 +293,8 @@ public void setSource(Account account, AccountTransaction transaction)
this.dividendAmount = calculateDividendAmount();

this.note = transaction.getNote();

this.nonCashEffective = transaction.getNonCashEffective();
}

@Override
Expand Down Expand Up @@ -663,6 +673,17 @@ public void setNote(String note)
firePropertyChange(Properties.note.name(), this.note, this.note = note);
}

public boolean getNonCashEffective()
{
return nonCashEffective;
}

public void setNonCashEffective(boolean nonCashEffective)
{
firePropertyChange(Properties.nonCashEffective.name(), this.nonCashEffective,
this.nonCashEffective = nonCashEffective);
}

public String getAccountCurrencyCode()
{
return account != null ? account.getCurrencyCode() : ""; //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2601,3 +2601,11 @@ WatchlistRename = Rename Watchlist
Website = Website

YearlyPerformanceHeatmapToolTip = Yearly rate of return displayed as heatmap\n\nTo calculate the yearly rate of return, the true-time weighted rate of return (TTWROR) is used.\n\nThe rate of return is always calculated for the full year - even if the reporting interval ends or starts in the middle of a year.

LabelNonCashEffective = Dividend is non cash-effective

MenuNonCashEffective = Exclude non cash-effective dividends

MsgInfoNonCashEffective = Non cash-effective dividend payments can be excluded in the payment view. This can be used, e.g., for spin-offs and stock dividends.

TransactionFilterNonCashEffectiveDividend = Non cash-effective dividends
Original file line number Diff line number Diff line change
Expand Up @@ -2594,3 +2594,11 @@ WatchlistRename = Watchliste umbenennen
Website = Website

YearlyPerformanceHeatmapToolTip = Jahresrenditen in einer Heatmap\n\nZur Berechnung der Jahresrendite wird der True-Time Weighted Rate of Return (TTWROR) herangezogen.\n\nDie Rendite bezieht sich immer auf das gesamte Jahr - selbst wenn der Berichtszeitraum in der Mitte des Jahres beginnt bzw. endet.

LabelNonCashEffective = Dividende ist nicht zahlungswirksam

MenuNonCashEffective = Nicht zahlungswirksame Dividenden ausschlie\u00DFen

MsgInfoNonCashEffective = Nicht zahlungswirksame Dividenden k\u00F6nnen in der Ansicht Zahlungen ausgeschlossen werden. Dies kann z.B. f\u00FCr Spin-Off oder Aktiendividende verwendet werden.

TransactionFilterNonCashEffectiveDividend = nicht zahlungswirksame Dividenden
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ else if (tx instanceof AccountTransaction atx)
else
return false;
}), //
NON_CASH_EFFECTIVE_DIVIDEND(Messages.TransactionFilterNonCashEffectiveDividend, 1, tx -> {
if (tx instanceof AccountTransaction atx)
return atx.getType() == AccountTransaction.Type.DIVIDENDS && atx.getNonCashEffective();
else
return false;
}), //
DEPOSIT_AND_REMOVAL(Messages.TransactionFilterDepositAndRemoval, 0, tx -> {
if (tx instanceof AccountTransaction atx)
return atx.getType() == AccountTransaction.Type.DEPOSIT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public void linkActivated(HyperlinkEvent e)
GrossNetType grossNetType = get(GrossNetTypeConfig.class).getValue();

part.activateView(PaymentsView.class, new PaymentsViewInput(tab, startYear, Optional.of(filterIdent),
mode, grossNetType == GrossNetType.GROSS, false));
mode, grossNetType == GrossNetType.GROSS, false, true));
}
});

Expand All @@ -155,7 +155,7 @@ public Supplier<PaymentsViewModel> getUpdateTask()
return () -> (PaymentsViewModel) getDashboardData().getCache().computeIfAbsent(key, k -> {
PaymentsViewModel model = new PaymentsViewModel(converter, getClient());
PaymentsViewModel.Mode mode = earningsType.getPaymentsViewModelMode();
model.configure(startYear, mode, grossNetType == GrossNetType.GROSS, false);
model.configure(startYear, mode, grossNetType == GrossNetType.GROSS, false, true);
model.setFilteredClient(clientFilter.filter(getClient()));
model.recalculate();
return model;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,14 @@ public void setupModel()
loadSavedFilterIdAndSetFilteredClientToModel();

model.configure(viewInput.getYear(), viewInput.getMode(), viewInput.isUseGrossValue(),
viewInput.isUseConsolidateRetired());
viewInput.isUseConsolidateRetired(), viewInput.isExcludeNonCashEffective());

model.addUpdateListener(() -> {
viewInput.setYear(model.getStartYear());
viewInput.setMode(model.getMode());
viewInput.setUseGrossValue(model.usesGrossValue());
viewInput.setUseConsolidateRetired(model.usesConsolidateRetired());
viewInput.setExcludeNonCashEffective(model.excludeNonCashEffective());
});
}

Expand Down Expand Up @@ -191,6 +192,12 @@ protected void addButtons(ToolBarManager toolBar)
action.setChecked(model.usesConsolidateRetired());
manager.add(action);

// toggle non cash-effective dividends
action = new SimpleAction(Messages.MenuNonCashEffective,
a -> model.setExcludeNonCashEffective(!model.excludeNonCashEffective()));
action.setChecked(model.excludeNonCashEffective());
manager.add(action);

PaymentsTab tab = (PaymentsTab) folder.getSelection().getData();
if (tab != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class PaymentsViewInput
private static final String KEY_USE_CONSOLIDATE_RETIRED = PaymentsView.class.getSimpleName()
+ "-use-consolidate-retired"; //$NON-NLS-1$
// for legacy reasons, the key is stored with the name PaymentsViewModel
private static final String KEY_EXCLUDE_NON_CASH_EFFECTIVE = PaymentsView.class.getSimpleName()
+ "-exclude-non-cash-effective"; //$NON-NLS-1$
private static final String KEY_USED_FILTER = PaymentsViewModel.class.getSimpleName();

private int tab;
Expand All @@ -26,16 +28,18 @@ public class PaymentsViewInput
private PaymentsViewModel.Mode mode;
private boolean useGrossValue;
private boolean useConsolidateRetired;
private boolean excludeNonCashEffective;

public PaymentsViewInput(int tab, int year, Optional<String> filterIdent, Mode mode, boolean useGrossValue,
boolean useConsolidateRetired)
boolean useConsolidateRetired, boolean excludeNonCashEffective)
{
this.tab = tab;
this.year = year;
this.clientFilterId = filterIdent;
this.mode = mode;
this.useGrossValue = useGrossValue;
this.useConsolidateRetired = useConsolidateRetired;
this.excludeNonCashEffective = excludeNonCashEffective;
}

public int getTab()
Expand Down Expand Up @@ -98,6 +102,16 @@ public void setUseConsolidateRetired(boolean useConsolidateRetired)
this.useConsolidateRetired = useConsolidateRetired;
}

public boolean isExcludeNonCashEffective()
{
return excludeNonCashEffective;
}

public void setExcludeNonCashEffective(boolean excludeNonCashEffective)
{
this.excludeNonCashEffective = excludeNonCashEffective;
}

public static PaymentsViewInput fromPreferences(IPreferenceStore preferences, Client client)
{
int tab = preferences.getInt(KEY_TAB);
Expand Down Expand Up @@ -126,8 +140,9 @@ public static PaymentsViewInput fromPreferences(IPreferenceStore preferences, Cl

boolean useGrossValue = preferences.getBoolean(KEY_USE_GROSS_VALUE);
boolean useConsolidateRetired = preferences.getBoolean(KEY_USE_CONSOLIDATE_RETIRED);
boolean excludeNonCashEffective = preferences.getBoolean(KEY_EXCLUDE_NON_CASH_EFFECTIVE);

return new PaymentsViewInput(tab, year, clientFilterId, mode, useGrossValue, useConsolidateRetired);
return new PaymentsViewInput(tab, year, clientFilterId, mode, useGrossValue, useConsolidateRetired, excludeNonCashEffective);
}

public void writeToPreferences(IPreferenceStore preferences, Client client)
Expand All @@ -137,6 +152,7 @@ public void writeToPreferences(IPreferenceStore preferences, Client client)
preferences.setValue(KEY_MODE, mode.name());
preferences.setValue(KEY_USE_GROSS_VALUE, useGrossValue);
preferences.setValue(KEY_USE_CONSOLIDATE_RETIRED, useConsolidateRetired);
preferences.setValue(KEY_EXCLUDE_NON_CASH_EFFECTIVE, excludeNonCashEffective);

ClientFilterMenu.saveSelectedFilter(client, KEY_USED_FILTER, clientFilterId.orElse("")); //$NON-NLS-1$
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public <T> T adapt(Class<T> type)
private Mode mode = Mode.ALL;
private boolean useGrossValue = true;
private boolean useConsolidateRetired = true;
private boolean excludeNonCashEffective = true;

public PaymentsViewModel(CurrencyConverter converter, Client client)
{
Expand All @@ -158,12 +159,14 @@ public PaymentsViewModel(CurrencyConverter converter, Client client)
this.filteredClient = client;
}

public void configure(int startYear, Mode mode, boolean useGrossValue, boolean useConsolidateRetired)
public void configure(int startYear, Mode mode, boolean useGrossValue, boolean useConsolidateRetired,
boolean excludeNonCashEffective)
{
this.startYear = startYear;
this.mode = mode;
this.useGrossValue = useGrossValue;
this.useConsolidateRetired = useConsolidateRetired;
this.excludeNonCashEffective = excludeNonCashEffective;

recalculate();
}
Expand Down Expand Up @@ -236,6 +239,17 @@ public void setUseConsolidateRetired(boolean useConsolidateRetired)
recalculate();
}

public boolean excludeNonCashEffective()
{
return excludeNonCashEffective;
}

public void setExcludeNonCashEffective(boolean excludeNonCashEffective)
{
this.excludeNonCashEffective = excludeNonCashEffective;
recalculate();
}

/**
* Returns all lines including the sum line
*/
Expand Down Expand Up @@ -389,6 +403,9 @@ private void calculate()
if (!checkIsInInterval.test(transaction))
continue;

if (excludeNonCashEffective && transaction.getNonCashEffective())
continue;

long value = 0;
switch (mode)
{
Expand Down
Loading