2024-09-19 19:12:23 +00:00
|
|
|
module util.sample_data;
|
|
|
|
|
|
|
|
import slf4d;
|
2024-09-27 15:35:08 +00:00
|
|
|
import handy_httpd.components.optional;
|
2024-09-19 19:12:23 +00:00
|
|
|
|
|
|
|
import auth;
|
|
|
|
import profile;
|
|
|
|
import account;
|
2024-09-27 15:35:08 +00:00
|
|
|
import transaction;
|
2024-09-19 19:12:23 +00:00
|
|
|
import util.money;
|
|
|
|
|
|
|
|
import std.random;
|
|
|
|
import std.conv;
|
|
|
|
import std.array;
|
2024-09-27 15:35:08 +00:00
|
|
|
import std.datetime;
|
2024-09-19 19:12:23 +00:00
|
|
|
|
|
|
|
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++) {
|
2024-09-27 15:35:08 +00:00
|
|
|
try {
|
|
|
|
generateRandomUser(i, userRepo);
|
|
|
|
} catch (Throwable t) {
|
|
|
|
import std.stdio;
|
|
|
|
stderr.writeln(t);
|
|
|
|
throw t;
|
|
|
|
}
|
2024-09-19 19:12:23 +00:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
2024-09-27 15:35:08 +00:00
|
|
|
|
|
|
|
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);
|
2024-09-19 19:12:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
);
|
2024-09-27 15:35:08 +00:00
|
|
|
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));
|
|
|
|
}
|
2024-09-19 19:12:23 +00:00
|
|
|
}
|