100 lines
2.9 KiB
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
|
|
);
|
|
} |