finnow/finnow-api/source/analytics/balances.d

100 lines
2.9 KiB
D

module analytics.balances;
import handy_http_primitives;
import std.datetime;
import std.stdio;
import std.path;
import std.file;
import slf4d;
import asdf;
import profile.data;
import profile.model;
import account.data;
import account.model;
import account.service;
import analytics.util;
struct BalanceSnapshot {
long balance;
string timestamp;
}
struct AccountBalanceTimeSeries {
ulong accountId;
string currencyCode;
BalanceSnapshot[] balanceTimeSeries;
}
struct TotalBalanceTimeSeries {
string currencyCode;
BalanceSnapshot[] balanceTimeSeries;
}
struct BalanceTimeSeriesAnalytics {
AccountBalanceTimeSeries[] accounts;
TotalBalanceTimeSeries[] totals;
}
void computeAccountBalanceTimeSeries(Profile profile, ProfileRepository profileRepo) {
ProfileDataSource ds = profileRepo.getDataSource(profile);
Account[] accounts = ds.getAccountRepository().findAll();
// Initialize the data structure that'll store the analytics info.
BalanceTimeSeriesAnalytics data;
foreach (account; accounts) {
data.accounts ~= AccountBalanceTimeSeries(
account.id,
account.currency.code.idup,
[]
);
}
foreach (timestamp; generateTimeSeriesTimestamps(days(1), 365)) {
// Compute the balance of each account at this timestamp.
foreach (idx, account; accounts) {
auto balance = getBalance(ds, account.id, timestamp);
if (!balance.isNull) {
data.accounts[idx].balanceTimeSeries ~= BalanceSnapshot(
balance.value,
timestamp.toISOExtString()
);
}
}
// Compute total balances for this timestamp.
auto totalBalances = getTotalBalanceForAllAccounts(ds, timestamp);
foreach (bal; totalBalances) {
// Assign the balance to one of our running totals.
bool currencyFound = false;
foreach (ref currencyTotal; data.totals) {
if (currencyTotal.currencyCode == bal.currency.code) {
currencyTotal.balanceTimeSeries ~= BalanceSnapshot(
bal.balance,
timestamp.toISOExtString()
);
currencyFound = true;
break;
}
}
if (!currencyFound) {
data.totals ~= TotalBalanceTimeSeries(
bal.currency.code.idup,
[BalanceSnapshot(bal.balance, timestamp.toISOExtString())]
);
}
}
}
ds.doTransaction(() {
ds.getPropertiesRepository().deleteAllByPrefix("analytics");
ds.getPropertiesRepository().setProperty(
"analytics.balanceTimeSeries",
serializeToJsonPretty(data)
);
});
infoF!"Computed account balance analytics for user %s, profile %s."(
profile.username,
profile.name
);
}