Skip to content

Commit

Permalink
Merge pull request #112 from andywuest/dividend_calculation_fix
Browse files Browse the repository at this point in the history
Dividend calculation fix
  • Loading branch information
andywuest committed Apr 4, 2024
2 parents 6960d1b + a4fc069 commit 8c4b96e
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 47 deletions.
4 changes: 3 additions & 1 deletion rpm/harbour-watchlist.changes.in
Expand Up @@ -5,9 +5,11 @@
# * date Author's Name <author's email> version-release
# - Summary of changes

* xx.xx.2024 Andreas Wüst <andreas.wuest.freelancer@gmail.com> 0.13.4-1
* 04.04.2024 Andreas Wüst <andreas.wuest.freelancer@gmail.com> 0.13.4-1

- hide dividends payed in the past (for current month)
- fixed calculation of total dividend (if number of securities is maintained)
- added testcase / testcase cleanup

* 07.03.2024 Andreas Wüst <andreas.wuest.freelancer@gmail.com> 0.13.3-1

Expand Down
34 changes: 21 additions & 13 deletions src/dividenddata/dividenddataupdateworker.cpp
Expand Up @@ -70,27 +70,27 @@ void DividendDataUpdateWorker::performUpdate() {
QJsonObject rootObject = jsonDocument.object();
QJsonArray dividendsArray = rootObject["dividends"].toArray();

QVariant empty;
const QString convertedEuroCurrency = convertCurrency("EUR");
const QString query = QString(
"INSERT INTO dividends(exDate, exDateInteger, payDate, payDateInteger, isin, wkn, "
"symbol, amount, currency, convertedAmount, convertedAmountCurrency) ")
+ QString("VALUES (:exDate, :exDateInteger, :payDate, :payDateInteger, :isin, :wkn, "
":symbol, :amount, :currency, :convertedAmount, :convertedAmountCurrency)");

const QTime defaultTime = QTime(0, 0);

// TODO run in worker
foreach (const QJsonValue &dividendsEntry, dividendsArray) {
QJsonObject dividendsObject = dividendsEntry.toObject();

// add new ones
QDate payDate = QDate::fromString(dividendsObject["payDate"].toString(), "yyyy-MM-dd");
QDate exDate = QDate::fromString(dividendsObject["exDate"].toString(), "yyyy-MM-dd");
QDateTime payDateTime = QDateTime(payDate, QTime(0, 0), Qt::LocalTime);
QDateTime exDateTime = QDateTime(exDate, QTime(0, 0), Qt::LocalTime);

QString query = QString("INSERT INTO dividends(exDate, exDateInteger, payDate, payDateInteger, isin, wkn, "
"symbol, amount, currency, convertedAmount, convertedAmountCurrency) ")
+ QString("VALUES (:exDate, :exDateInteger, :payDate, :payDateInteger, :isin, :wkn, "
":symbol, :amount, :currency, :convertedAmount, :convertedAmountCurrency)");
QDateTime payDateTime = QDateTime(payDate, defaultTime, Qt::LocalTime);
QDateTime exDateTime = QDateTime(exDate, defaultTime, Qt::LocalTime);

double amount = dividendsObject["amount"].toDouble();
QString currency = dividendsObject["currency"].toString();
bool hasConvertedAmount = this->exchangeRateMap.contains(currency);
double convertedAmount = (hasConvertedAmount ? (amount / this->exchangeRateMap[currency].toDouble()) : 0.0);
double convertedAmount = calculateConvertedAmount(amount, currency);

QMap<QString, QVariant> dataMap;
dataMap.insert(":exDate", exDate.toString("dd.MM.yyyy"));
Expand All @@ -103,8 +103,8 @@ void DividendDataUpdateWorker::performUpdate() {
dataMap.insert(":symbol", dividendsObject["symbol"].toString());
dataMap.insert(":amount", amount);
dataMap.insert(":currency", convertCurrency(currency));
dataMap.insert(":convertedAmount", hasConvertedAmount ? convertedAmount : empty);
dataMap.insert(":convertedAmountCurrency", hasConvertedAmount ? convertCurrency("EUR") : empty);
dataMap.insert(":convertedAmount", convertedAmount);
dataMap.insert(":convertedAmountCurrency", convertedEuroCurrency);

executeQuery(query, dataMap);
rows++;
Expand All @@ -119,6 +119,14 @@ void DividendDataUpdateWorker::performUpdate() {
emit updateCompleted(rows);
}

double DividendDataUpdateWorker::calculateConvertedAmount(double amount, QString currency) {
if (QString("EUR").compare(currency) == 0) {
return amount;
}
bool hasConvertedAmount = this->exchangeRateMap.contains(currency);
return (hasConvertedAmount ? (amount / this->exchangeRateMap[currency].toDouble()) : 0.0);
}

void DividendDataUpdateWorker::executeQuery(const QString &queryString, const QMap<QString, QVariant> &dataMap) {
if (database.open()) {
QSqlQuery query;
Expand Down
5 changes: 5 additions & 0 deletions src/dividenddata/dividenddataupdateworker.h
Expand Up @@ -45,6 +45,7 @@ class DividendDataUpdateWorker : public QThread {

protected:
QString convertCurrency(const QString &currencyString);
double calculateConvertedAmount(double amount, QString currency);

private:
QSqlDatabase database;
Expand All @@ -53,6 +54,10 @@ class DividendDataUpdateWorker : public QThread {

void performUpdate();
void executeQuery(const QString &queryString, const QMap<QString, QVariant> &dataMap);

#ifdef UNIT_TEST
friend class WatchlistTests; // to test non public methods
#endif
};

#endif // DIVIDEND_DATA_UPDATE_WORKER_H
2 changes: 1 addition & 1 deletion src/newsdata/ingdibanews.h
Expand Up @@ -49,7 +49,7 @@ private slots:
void handleSearchStockNews();

#ifdef UNIT_TEST
friend class IngDibaBackendTests; // to test non public methods
friend class WatchlistTests; // to test non public methods
#endif
};

Expand Down
2 changes: 1 addition & 1 deletion src/securitydata/ingdibabackend.h
Expand Up @@ -66,7 +66,7 @@ private slots:
void handleFetchPricesForChartFinished();

#ifdef UNIT_TEST
friend class IngDibaBackendTests;
friend class WatchlistTests;
#endif
};

Expand Down
2 changes: 1 addition & 1 deletion test/cpp/.gitignore
@@ -1,3 +1,3 @@
moc_*.h
.qmake*
/IngDibaBackendTest
/WatchlistTests
6 changes: 3 additions & 3 deletions test/cpp/harbour-watchlist-tests.pro
Expand Up @@ -4,15 +4,15 @@ QT -= gui
CONFIG += c++11 qt

SOURCES += testmain.cpp \
ingdibabackendtests.cpp
watchlisttests.cpp

HEADERS += \
ingdibabackendtests.h
watchlisttests.h

INCLUDEPATH += ../../
include(../../harbour-watchlist.pri)

TARGET = IngDibaBackendTest
TARGET = WatchlistTests

DISTFILES += \
testdata/ie00b57x3v84.json \
Expand Down
2 changes: 1 addition & 1 deletion test/cpp/runTests.sh
Expand Up @@ -9,7 +9,7 @@ find . -name "Makefile" -exec rm {} \;

qmake -o Makefile harbour-watchlist-tests.pro
make
env LC_ALL=de_DE.UTF-8 LC_NUMERIC=de_DE.utf8 ./IngDibaBackendTest -junitxml -o junit.xml
env LC_ALL=de_DE.UTF-8 LC_NUMERIC=de_DE.utf8 ./WatchlistTests -junitxml -o junit.xml



4 changes: 2 additions & 2 deletions test/cpp/testmain.cpp
@@ -1,4 +1,4 @@
#include "ingdibabackendtests.h"
#include "watchlisttests.h"
#include <QtTest/QtTest>

QTEST_GUILESS_MAIN(IngDibaBackendTests)
QTEST_GUILESS_MAIN(WatchlistTests)
49 changes: 29 additions & 20 deletions test/cpp/ingdibabackendtests.cpp → test/cpp/watchlisttests.cpp
Expand Up @@ -15,16 +15,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ingdibabackendtests.h"
#include "watchlisttests.h"
#include <QtTest/QtTest>

// TODO rename
void IngDibaBackendTests::init() {
void WatchlistTests::init() {
ingDibaBackend = new IngDibaBackend(nullptr, nullptr);
ingDibaNews = new IngDibaNews(nullptr, nullptr);
dividendDataUpdateWorker = new DividendDataUpdateWorker(nullptr);
}

void IngDibaBackendTests::testIngDibaUtilsConvertTimestampToLocalTimestamp() {
void WatchlistTests::testIngDibaUtilsConvertTimestampToLocalTimestamp() {
qDebug() << "dir : " << QCoreApplication::applicationFilePath();
qDebug() << "Timezone for test : " << QTimeZone::systemTimeZone();
QString testDate = QString("2020-10-14T20:22:24+02:00");
Expand All @@ -34,38 +34,32 @@ void IngDibaBackendTests::testIngDibaUtilsConvertTimestampToLocalTimestamp() {
QCOMPARE(dateTimeFormatted, QString("2020-10-14 20:22:24"));
}

void IngDibaBackendTests::testIngDibaBackendIsValidSecurityCategory() {
void WatchlistTests::testIngDibaBackendIsValidSecurityCategory() {
QCOMPARE(ingDibaBackend->isValidSecurityCategory("Fonds"), true);
QCOMPARE(ingDibaBackend->isValidSecurityCategory("Aktien"), true);
QCOMPARE(ingDibaBackend->isValidSecurityCategory("etfs"), true);
QCOMPARE(ingDibaBackend->isValidSecurityCategory("NIX"), false);
}

void IngDibaBackendTests::testIngDibaBackendProcessSearchResult() {
// TODO use readFileData

QString testFile = "ie00b57x3v84.json";
QFile f("testdata/" + testFile);
if (!f.open(QFile::ReadOnly | QFile::Text)) {
QString msg = "Testfile " + testFile + " not found!";
QFAIL(msg.toLocal8Bit().data());
void WatchlistTests::testIngDibaBackendProcessSearchResult() {
QByteArray data = readFileData("ie00b57x3v84.json");
if (data.isEmpty()) {
QFAIL("Testfile ie00b57x3v84.json not found!");
}

QTextStream in(&f);
QByteArray data = in.readAll().toUtf8();
QString parsedResult = ingDibaBackend->processSearchResult(data);
QJsonDocument jsonDocument = QJsonDocument::fromJson(parsedResult.toUtf8());
QCOMPARE(jsonDocument.isArray(), true);
QJsonArray resultArray = jsonDocument.array();
QCOMPARE(resultArray.size(), 1);
}

void IngDibaBackendTests::testIngDibaNewsProcessSearchResult() {
void WatchlistTests::testIngDibaNewsProcessSearchResult() {
QByteArray data = readFileData("ing_news.json");
if (data.isEmpty()) {
QString msg = "Testfile ing_news.json not found!";
QFAIL(msg.toLocal8Bit().data());
QFAIL("Testfile ing_news.json not found!");
}

QString parsedResult = ingDibaNews->processSearchResult(data);
QJsonDocument jsonDocument = QJsonDocument::fromJson(parsedResult.toUtf8());
QCOMPARE(jsonDocument.isObject(), true);
Expand All @@ -81,7 +75,7 @@ void IngDibaBackendTests::testIngDibaNewsProcessSearchResult() {
// TODO QCOMPARE first news data entry
}

void IngDibaBackendTests::testIngDibaNewsFilterContent() {
void WatchlistTests::testIngDibaNewsFilterContent() {
QString content = "<p>\n FRANKFURT (Dow Jones)--In der deutschen </p>\n<p>\n Die Vereinigten Staaten .. Lage "
"wünschenswert. </p>\n<p>\n Kontakt zum Autor: unternehmen.de@dowjones.com </p>\n<p>\n DJG/sha "
"</p>\n<p>\n (END) <a href=\"/DE/Showpage.aspx?pageID=45&ISIN=US2605661048&\" title=\"Übersicht "
Expand All @@ -92,7 +86,22 @@ void IngDibaBackendTests::testIngDibaNewsFilterContent() {
QCOMPARE(ingDibaNews->filterContent(content), expectedContent);
}

QByteArray IngDibaBackendTests::readFileData(const QString &fileName) {
void WatchlistTests::testDividendDataUpdateWorkerCalculateConvertedAmount() {
// given
QMap<QString, QVariant> exchangeRateMap;
exchangeRateMap.insert("USD", 0.8);
exchangeRateMap.insert("CHF", 1.2);
dividendDataUpdateWorker->setParameters(QJsonDocument(), exchangeRateMap);

// when - then
QCOMPARE(dividendDataUpdateWorker->calculateConvertedAmount(1.6, QString("EUR")), 1.6);
QCOMPARE(dividendDataUpdateWorker->calculateConvertedAmount(1.4, QString("EUR")), 1.4);
QCOMPARE(dividendDataUpdateWorker->calculateConvertedAmount(2.0, QString("USD")), 2.5);
QCOMPARE(dividendDataUpdateWorker->calculateConvertedAmount(6, QString("CHF")), 5);
QCOMPARE(dividendDataUpdateWorker->calculateConvertedAmount(1.4, QString("GBP")), 0.0);
}

QByteArray WatchlistTests::readFileData(const QString &fileName) {
QFile f("testdata/" + fileName);
if (!f.open(QFile::ReadOnly | QFile::Text)) {
QString msg = "Testfile " + fileName + " not found!";
Expand Down
13 changes: 9 additions & 4 deletions test/cpp/ingdibabackendtests.h → test/cpp/watchlisttests.h
Expand Up @@ -15,19 +15,21 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ING_DIBA_BACKEND_TEST_H
#define ING_DIBA_BACKEND_TEST_H
#ifndef WATCHLIST_TESTS_H
#define WATCHLIST_TESTS_H

#include <QObject>

#include "src/dividenddata/dividenddataupdateworker.h"
#include "src/ingdibautils.h"
#include "src/newsdata/ingdibanews.h"
#include "src/securitydata/ingdibabackend.h"

class IngDibaBackendTests : public QObject {
class WatchlistTests : public QObject {
Q_OBJECT

private:
DividendDataUpdateWorker *dividendDataUpdateWorker;
IngDibaBackend *ingDibaBackend;
IngDibaNews *ingDibaNews;

Expand All @@ -45,6 +47,9 @@ private slots:
// ING-DIBA News Backend
void testIngDibaNewsProcessSearchResult();
void testIngDibaNewsFilterContent();

// DividendDataUpdate Worker
void testDividendDataUpdateWorkerCalculateConvertedAmount();
};

#endif // ING_DIBA_BACKEND_TEST_H
#endif // WATCHLIST_TESTS_H

0 comments on commit 8c4b96e

Please sign in to comment.