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

added widget for the dashboard and columns for the information of dividends #3927

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 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
@@ -0,0 +1,294 @@
package name.abuchen.portfolio.ui.views.dashboard;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.model.SecurityEvent;
import name.abuchen.portfolio.model.SecurityEvent.DividendEvent;
import name.abuchen.portfolio.money.Money;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.views.dashboard.DividendListWidget.DateEndRange;
import name.abuchen.portfolio.ui.views.dashboard.DividendListWidget.DateStartRange;
import name.abuchen.portfolio.ui.views.dashboard.DividendListWidget.DateType;
import name.abuchen.portfolio.ui.views.dashboard.DividendListWidget.DividendItem;

@SuppressWarnings("nls")
public class DividendListWidgetTest
kimmerin marked this conversation as resolved.
Show resolved Hide resolved
{
private static Locale defaultLocale;

private Security sec1;
private Security sec2;
private DividendEvent de1_1;
private DividendEvent de1_2;
private SecurityEvent de1_3;
private DividendEvent de1_4;
private DividendEvent de1_5;
private DividendEvent de2_1;
private DividendEvent de2_2;
private SecurityEvent de2_3;
private DividendEvent de2_4;

@BeforeClass
public static void setupLocale()
{
defaultLocale = Locale.getDefault();
Locale.setDefault(Locale.GERMANY);
}

@AfterClass
public static void resetLocale()
{
Locale.setDefault(defaultLocale);
}

@Before
public void setupTestData()
{
sec1 = new Security("Security 1", "EUR");
de1_1 = new DividendEvent(LocalDate.of(2024, 4, 9), LocalDate.of(2024, 4, 12), Money.of("EUR", 55), "source");
de1_2 = new DividendEvent(LocalDate.of(2024, 7, 14), LocalDate.of(2024, 8, 11), Money.of("EUR", 22), "source");
de1_3 = new SecurityEvent(LocalDate.of(2024, 2, 3), SecurityEvent.Type.NOTE, "some note");
de1_4 = new DividendEvent(LocalDate.of(2024, 2, 4), LocalDate.of(2024, 3, 5), Money.of("EUR", 33), "source");
de1_5 = new DividendEvent(LocalDate.of(2024, 8, 1), LocalDate.of(2024, 8, 1), Money.of("EUR", 33), "source");
sec1.addEvent(de1_1);
sec1.addEvent(de1_2);
sec1.addEvent(de1_3);
sec1.addEvent(de1_4);

sec2 = new Security("Security 2", "EUR");
de2_1 = new DividendEvent(LocalDate.of(2024, 4, 5), LocalDate.of(2024, 4, 9), Money.of("USD", 55), "source");
de2_2 = new DividendEvent(LocalDate.of(2024, 7, 14), LocalDate.of(2024, 7, 15), Money.of("USD", 122), "source");
de2_3 = new SecurityEvent(LocalDate.of(2024, 8, 25), SecurityEvent.Type.STOCK_SPLIT, "some stock split");
de2_4 = new DividendEvent(LocalDate.of(2024, 2, 5), LocalDate.of(2024, 3, 5), Money.of("USD", 1333), "source");
sec2.addEvent(de2_1);
sec2.addEvent(de2_2);
sec2.addEvent(de2_3);
sec2.addEvent(de2_4);

}

@Test
public void testDividendItemInstantiation()
{
DividendItem di;

di = new DividendItem(DateType.EX_DIVIDEND_DATE, sec1, de1_1);
assertThat(di.getSecurity(), is(sec1));
assertThat(di.getFirstType(), is(DateType.EX_DIVIDEND_DATE));
assertThat(di.div, is(de1_1));
}

@Test
public void testDateStartRange()
{
assertEquals("FROM_TODAY,FROM_ONE_WEEK,FROM_ONE_MONTH,FROM_QUARTER", //
Arrays.stream(DateStartRange.values())
.map(DateStartRange::name).collect(Collectors.joining(",")));

LocalDate now = LocalDate.of(2024, 4, 8);
assertThat(DateStartRange.FROM_TODAY.getDate(now), is(now));
assertThat(DateStartRange.FROM_ONE_WEEK.getDate(now), is(LocalDate.of(2024, 4, 1)));
assertThat(DateStartRange.FROM_ONE_MONTH.getDate(now), is(LocalDate.of(2024, 3, 8)));
assertThat(DateStartRange.FROM_QUARTER.getDate(now), is(LocalDate.of(2024, 1, 8)));
}

@Test
public void testDateEndRange()
{
assertEquals("UNTIL_ALL,UNTIL_EOY,UNTIL_ONE_MONTH,UNTIL_ONE_WEEK,UNTIL_TODAY", //
Arrays.stream(DateEndRange.values()).map(DateEndRange::name).collect(Collectors.joining(",")));

LocalDate now = LocalDate.of(2024, 4, 8);
assertThat(DateEndRange.UNTIL_TODAY.getDate(now), is(now));
assertThat(DateEndRange.UNTIL_ONE_WEEK.getDate(now), is(LocalDate.of(2024, 4, 15)));
assertThat(DateEndRange.UNTIL_ONE_MONTH.getDate(now), is(LocalDate.of(2024, 5, 8)));
assertThat(DateEndRange.UNTIL_EOY.getDate(now), is(LocalDate.of(2024, 12, 31)));
assertThat(DateEndRange.UNTIL_ALL.getDate(now), nullValue());
}

@Test
public void testDateType()
{
assertEquals("ALL_DATES,EX_DIVIDEND_DATE,PAYMENT_DATE", //
Arrays.stream(DateType.values()).map(DateType::name).collect(Collectors.joining(",")));

assertThat(DateType.ALL_DATES.getDate(de1_1), nullValue());
assertThat(DateType.EX_DIVIDEND_DATE.getDate(de1_1), is(de1_1.getDate()));
assertThat(DateType.PAYMENT_DATE.getDate(de1_1), is(de1_1.getPaymentDate()));
}

@Test
public void testGetUpdateTask() throws Exception
{
LocalDate testnow = LocalDate.now();
AbstractSecurityListWidget<DividendItem> widget = new DividendListWidget()
{
@Override
public List<DividendItem> getUpdateTask(LocalDate now)
{
assertThat(now, is(testnow));
return null;
}
};
assertThat(widget.getUpdateTask().get(), nullValue());
}

@Test
public void testGetUpdateTaskNow()
{
List<DividendItem> list;
AtomicReference<DateStartRange> dateStart = new AtomicReference<>(DateStartRange.FROM_TODAY);
AtomicReference<DateEndRange> dateEnd = new AtomicReference<>(DateEndRange.UNTIL_TODAY);
AtomicReference<DateType> dateType = new AtomicReference<>(DateType.ALL_DATES);
AtomicBoolean showSecurities = new AtomicBoolean(true);

DividendListWidget widget = new DividendListWidget()
{
@Override
DateStartRange getStartRangeValue()
{
return dateStart.get();
}

@Override
DateEndRange getEndRangeValue()
{
return dateEnd.get();
}

@Override
DateType getDateTypeValue()
{
return dateType.get();
}

@Override
List<Security> getSecurities()
{
return Arrays.asList(sec1, sec2);
}

@Override
ClientFilterConfig getClientFilterConfig()
{
return null;
}

@Override
Set<Security> getSecuritiesToShow(ClientFilterConfig clientFilter)
{
if (showSecurities.get())
{
HashSet<Security> ret = new HashSet<>();
ret.addAll(getSecurities());
return ret;
}
return Collections.emptySet();
}
};

LocalDate now = LocalDate.of(2024, 4, 9);
list = widget.getUpdateTask(now);
assertEquals("2024-04-09 Security 1 EUR 0,55 [" + Messages.ColumnExDate + "]\r\n" //
+ "Security 2 USD 0,55 [" + Messages.ColumnPaymentDate + "]", getListAsString(list));

now = LocalDate.of(2024, 4, 8);
list = widget.getUpdateTask(now);
assertEquals("", getListAsString(list));

dateStart.set(DateStartRange.FROM_QUARTER);
list = widget.getUpdateTask(now);
assertEquals("2024-02-04 Security 1 EUR 0,33 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-02-05 Security 2 USD 13,33 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-03-05 Security 1 EUR 0,33 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "Security 2 USD 13,33 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-04-05 Security 2 USD 0,55 [" + Messages.ColumnExDate + "]", getListAsString(list));

dateEnd.set(DateEndRange.UNTIL_EOY);
list = widget.getUpdateTask(now);
assertEquals("2024-02-04 Security 1 EUR 0,33 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-02-05 Security 2 USD 13,33 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-03-05 Security 1 EUR 0,33 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "Security 2 USD 13,33 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-04-05 Security 2 USD 0,55 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-04-09 Security 1 EUR 0,55 [" + Messages.ColumnExDate + "]\r\n" //
+ "Security 2 USD 0,55 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-04-12 Security 1 EUR 0,55 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-07-14 Security 1 EUR 0,22 [" + Messages.ColumnExDate + "]\r\n" //
+ "Security 2 USD 1,22 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-07-15 Security 2 USD 1,22 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-08-11 Security 1 EUR 0,22 [" + Messages.ColumnPaymentDate + "]", getListAsString(list));

dateType.set(DateType.EX_DIVIDEND_DATE);
list = widget.getUpdateTask(now);
assertEquals("2024-02-04 Security 1 EUR 0,33 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-02-05 Security 2 USD 13,33 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-04-05 Security 2 USD 0,55 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-04-09 Security 1 EUR 0,55 [" + Messages.ColumnExDate + "]\r\n" //
+ "2024-07-14 Security 1 EUR 0,22 [" + Messages.ColumnExDate + "]\r\n" //
+ "Security 2 USD 1,22 [" + Messages.ColumnExDate + "]", getListAsString(list));

dateType.set(DateType.PAYMENT_DATE);
list = widget.getUpdateTask(now);
assertEquals("2024-03-05 Security 1 EUR 0,33 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "Security 2 USD 13,33 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-04-09 Security 2 USD 0,55 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-04-12 Security 1 EUR 0,55 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-07-15 Security 2 USD 1,22 [" + Messages.ColumnPaymentDate + "]\r\n" //
+ "2024-08-11 Security 1 EUR 0,22 [" + Messages.ColumnPaymentDate + "]", getListAsString(list));

sec1.getEvents().clear();
sec2.getEvents().clear();
sec1.addEvent(de1_5);
list = widget.getUpdateTask(now);
assertEquals("2024-08-01 Security 1 EUR 0,33 [" + Messages.ColumnPaymentDate + "]", getListAsString(list));
dateType.set(DateType.EX_DIVIDEND_DATE);
list = widget.getUpdateTask(now);
assertEquals("2024-08-01 Security 1 EUR 0,33 [" + Messages.ColumnExDate + "]", getListAsString(list));
dateType.set(DateType.ALL_DATES);
list = widget.getUpdateTask(now);
assertEquals("2024-08-01 Security 1 EUR 0,33 [" + Messages.ColumnExDate + ", " + Messages.ColumnPaymentDate
+ "]", getListAsString(list));

showSecurities.set(false);
list = widget.getUpdateTask(now);
assertEquals("", getListAsString(list));
}

private String getListAsString(List<DividendItem> list)
{
return list.stream() //
.map(entry -> {
StringBuilder sb = new StringBuilder();
if (entry.hasNewDate)
{
sb.append(entry.getFirstType().getDate(entry.div).toString() + " ");
}
sb.append(entry.getSecurity().getName() + " ");
sb.append(entry.div.getAmount() + " ");
sb.append(entry.types);
return sb.toString();
}) //
.collect(Collectors.joining("\r\n"));
}
}
3 changes: 2 additions & 1 deletion name.abuchen.portfolio.ui/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-Activator: name.abuchen.portfolio.ui.PortfolioPlugin
Bundle-Vendor: Andreas Buchen
Import-Package: com.google.common.base,
Import-Package: com.google.common.annotations,
com.google.common.base,
com.google.common.collect,
com.google.common.primitives,
com.google.gson,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,17 @@ public class Messages extends NLS
public static String OptionDateIsInTheFuture;
public static String OptionDateIsInThePast;
public static String YearlyPerformanceHeatmapToolTip;

public static String LabelEarningsDividendList;
public static String LabelEarningsDividendPeriodFrom;
public static String LabelEarningsDividendPeriodUntil;
public static String LabelEarningsDividendDateType;
public static String ColumnDividendsNextExDate;
public static String ColumnDividendsNextExDate_MenuLabel;
public static String ColumnDividendsNextPaymentDate;
public static String ColumnDividendsNextPaymentDate_MenuLabel;
public static String ColumnDividendsNextPaymentAmount;
public static String ColumnDividendsNextPaymentAmount_MenuLabel;
kimmerin marked this conversation as resolved.
Show resolved Hide resolved
static
{
// initialize resource bundle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,18 @@ ColumnDividendTotalRateOfReturn = Div%

ColumnDividendTotalRateOfReturn_Description = dividend rate of return = sum of dividend payments / purchase value based on FIFO\n\nAttention: if shares are sold after a dividend payment then dividend payment is not reduced. Therefore the rate of return might be over estimated.

ColumnDividendsNextExDate = Next Ex-Date

ColumnDividendsNextExDate_MenuLabel = Next Dividend Ex-Date

ColumnDividendsNextPaymentAmount = Next Paym. Amt.

ColumnDividendsNextPaymentAmount_MenuLabel = Next Dividend Payment Amount

ColumnDividendsNextPaymentDate = Next Paym. Date

ColumnDividendsNextPaymentDate_MenuLabel = Next Dividend Payment Date

ColumnEarnings = Earnings

ColumnEarnings_Description = Dividends + Interest Payments
Expand Down Expand Up @@ -1242,6 +1254,14 @@ LabelEarnings = Earnings

LabelEarningsByTaxonomy = Earnings by taxonomy

LabelEarningsDividendDateType = Type of date

LabelEarningsDividendList = Upcoming dividends

LabelEarningsDividendPeriodFrom = Period start

LabelEarningsDividendPeriodUntil = Period end

LabelEarningsPerMonth = Earnings per month

LabelEarningsPerQuarter = Earnings per quarter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,18 @@ ColumnDividendTotalRateOfReturn = Div%

ColumnDividendTotalRateOfReturn_Description = Dividendov\u00FD v\u00FDnos = sou\u010Det v\u00FDplat dividend / n\u00E1kupn\u00ED hodnota na z\u00E1klad\u011B FIFO\n\nPozor: pokud jsou akcie prod\u00E1ny po v\u00FDplat\u011B dividendy, pak se v\u00FDplata dividendy nesni\u017Euje. Proto m\u016F\u017Ee b\u00FDt m\u00EDra v\u00FDnosnosti nadhodnocena.

ColumnDividendsNextExDate = P\u0159\u00ED\u0161t\u00ED den ex-day

ColumnDividendsNextExDate_MenuLabel = P\u0159\u00ED\u0161t\u00ED Den Ex-Dividend

ColumnDividendsNextPaymentAmount = P\u0159\u00ED\u0161t\u00ED V\u00FD\u0161e Dividendy

ColumnDividendsNextPaymentAmount_MenuLabel = P\u0159\u00ED\u0161t\u00ED V\u00FD\u0161e Dividendy

ColumnDividendsNextPaymentDate = Datum P\u0159\u00ED\u0161t\u00ED V\u00FDplaty Dividend

ColumnDividendsNextPaymentDate_MenuLabel = Datum P\u0159\u00ED\u0161t\u00ED V\u00FDplaty Dividend

ColumnEarnings = Zisk

ColumnEarnings_Description = Dividendy + \u00FAroky
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,18 @@ ColumnDividendTotalRateOfReturn = Udb%

ColumnDividendTotalRateOfReturn_Description = udbytteafkast = summen af \u200B\u200Budbyttebetalinger / k\u00F8bsv\u00E6rdi baseret p\u00E5 FIFO\n\nBem\u00E6rk: Hvis aktier s\u00E6lges efter en udbyttebetaling, reduceres udbyttebetalingen ikke. Derfor kan afkastet v\u00E6re overvurderet.

ColumnDividendsNextExDate = N\u00E6ste Ex-Dato

ColumnDividendsNextExDate_MenuLabel = N\u00E6ste Ex-Udbyttedag

ColumnDividendsNextPaymentAmount = N\u00E6ste Udbyttebel\u00F8b

ColumnDividendsNextPaymentAmount_MenuLabel = N\u00E6ste Udbyttebel\u00F8b

ColumnDividendsNextPaymentDate = Dato for N\u00E6ste Udbyttebetaling

ColumnDividendsNextPaymentDate_MenuLabel = Dato for N\u00E6ste Udbyttebetaling

ColumnEarnings = Fortjenester

ColumnEarnings_Description = Udbytter + Renteindt\u00E6gter
Expand Down
Loading