finnow/finnow-api/source/util/sample_data.d

162 lines
5.5 KiB
D
Raw Permalink Normal View History

module util.sample_data;
import slf4d;
import handy_httpd.components.optional;
import auth;
import profile;
import account;
import transaction;
import util.money;
import std.random;
import std.conv;
import std.array;
import std.datetime;
void generateSampleData() {
UserRepository userRepo = new FileSystemUserRepository;
// Remove all existing user data.
foreach (User user; userRepo.findAll()) {
userRepo.deleteByUsername(user.username);
}
const int userCount = uniform(5, 10);
for (int i = 0; i < userCount; i++) {
try {
generateRandomUser(i, userRepo);
} catch (Throwable t) {
import std.stdio;
stderr.writeln(t);
throw t;
}
}
info("Random sample data generation complete.");
}
void generateRandomUser(int idx, UserRepository userRepo) {
string username = "testuser" ~ idx.to!string;
string password = "testpass";
infoF!"Generating random user %s, password: %s."(username, password);
User user = createNewUser(userRepo, username, password);
ProfileRepository profileRepo = new FileSystemProfileRepository(username);
const int profileCount = uniform(1, 5);
for (int i = 0; i < profileCount; i++) {
generateRandomProfile(i, profileRepo);
}
}
void generateRandomProfile(int idx, ProfileRepository profileRepo) {
string profileName = "test-profile-" ~ idx.to!string;
infoF!" Generating random profile %s."(profileName);
Profile profile = profileRepo.createProfile(profileName);
ProfileDataSource ds = profileRepo.getDataSource(profile);
ds.getPropertiesRepository().setProperty("sample-data-idx", idx.to!string);
const int accountCount = uniform(1, 10);
for (int i = 0; i < accountCount; i++) {
generateRandomAccount(i, ds);
}
auto vendorRepo = ds.getTransactionVendorRepository();
const int vendorCount = uniform(5, 30);
for (int i = 0; i < vendorCount; i++) {
vendorRepo.insert("Test Vendor " ~ to!string(i), "Testing vendor for sample data.");
}
infoF!" Generated %d random vendors."(vendorCount);
auto tagRepo = ds.getTransactionTagRepository();
const int tagCount = uniform(5, 30);
for (int i = 0; i < tagCount; i++) {
tagRepo.insert("test-tag-" ~ to!string(i));
}
infoF!" Generated %d random tags."(tagCount);
auto categoryRepo = ds.getTransactionCategoryRepository();
const int categoryCount = uniform(5, 30);
for (int i = 0; i < categoryCount; i++) {
categoryRepo.insert(Optional!ulong.empty, "Test Category " ~ to!string(i), "Testing category.", "FFFFFF");
}
infoF!" Generated %d random categories."(categoryCount);
generateRandomTransactions(ds);
}
void generateRandomAccount(int idx, ProfileDataSource ds) {
AccountRepository accountRepo = ds.getAccountRepository();
string idxStr = idx.to!string;
string numberSuffix = "0".replicate(4 - idxStr.length) ~ idxStr;
string name = "Test Account " ~ idxStr;
AccountType type = choice(ALL_ACCOUNT_TYPES);
Currency currency = choice(ALL_CURRENCIES);
string description = "This is a testing account generated by util.sample_data.generateRandomAccount().";
Account account = accountRepo.insert(
type,
numberSuffix,
name,
currency,
description
);
infoF!" Generated random account: %s, #%s"(name, numberSuffix);
}
void generateRandomTransactions(ProfileDataSource ds) {
const bool hasVendor = uniform01() > 0.3;
const bool hasCategory = uniform01() > 0.2;
const TransactionVendor[] vendors = ds.getTransactionVendorRepository.findAll();
const TransactionCategory[] categories = ds.getTransactionCategoryRepository()
.findAllByParentId(Optional!ulong.empty);
const TransactionTag[] tags = ds.getTransactionTagRepository().findAll();
const Account[] accounts = ds.getAccountRepository().findAll();
SysTime now = Clock.currTime(UTC());
SysTime timestamp = Clock.currTime(UTC()) - seconds(1);
for (int i = 0; i < 1000; i++) {
Optional!ulong vendorId;
if (hasVendor) {
vendorId = Optional!ulong.of(choice(vendors).id);
}
Optional!ulong categoryId;
if (hasCategory) {
categoryId = Optional!ulong.of(choice(categories).id);
}
Optional!ulong creditedAccountId;
Optional!ulong debitedAccountId;
Account primaryAccount = choice(accounts);
Optional!ulong secondaryAccount;
if (uniform01() < 0.25) {
foreach (acc; accounts) {
if (acc.id != primaryAccount.id && acc.currency == primaryAccount.currency) {
secondaryAccount.value = acc.id;
break;
}
}
}
if (uniform01() > 0.5) {
creditedAccountId = Optional!ulong.of(primaryAccount.id);
if (secondaryAccount) debitedAccountId = secondaryAccount;
} else {
debitedAccountId = Optional!ulong.of(primaryAccount.id);
if (secondaryAccount) creditedAccountId = secondaryAccount;
}
ulong value = uniform(0, 1_000_000);
addTransaction(
ds,
timestamp,
now,
value,
primaryAccount.currency,
"Test transaction " ~ to!string(i),
vendorId,
categoryId,
creditedAccountId,
debitedAccountId,
[]
);
infoF!" Generated transaction %d"(i);
timestamp -= seconds(uniform(10, 1_000_000));
}
}